MAPG-43 initial classes for DB handling
This commit is contained in:
		
							parent
							
								
									b821d4a045
								
							
						
					
					
						commit
						17c0ec73df
					
				
							
								
								
									
										114
									
								
								src/Database/Mysql/Connection.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/Database/Mysql/Connection.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					<?php namespace MapGuesser\Database\Mysql;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use MapGuesser\Interfaces\Database\IConnection;
 | 
				
			||||||
 | 
					use MapGuesser\Interfaces\Database\IResultSet;
 | 
				
			||||||
 | 
					use MapGuesser\Interfaces\Database\IStatement;
 | 
				
			||||||
 | 
					use mysqli;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Connection implements IConnection
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private mysqli $connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(string $host, string $user, string $password, string $db, int $port = -1, string $socket = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($port < 0) {
 | 
				
			||||||
 | 
					            $port = ini_get('mysqli.default_port');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($socket === null) {
 | 
				
			||||||
 | 
					            $socket = ini_get('mysqli.default_socket');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->connection = new mysqli($host, $user, $password, $db, $port, $socket);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->connection->connect_error) {
 | 
				
			||||||
 | 
					            throw new \Exception('Connection failed: ' . $this->connection->connect_error);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!$this->connection->set_charset('utf8mb4')) {
 | 
				
			||||||
 | 
					            throw new \Exception($this->connection->error);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __destruct()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->connection->close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function startTransaction(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!$this->connection->autocommit(false)) {
 | 
				
			||||||
 | 
					            throw new \Exception($this->connection->error);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function commit(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!$this->connection->commit() || !$this->connection->autocommit(true)) {
 | 
				
			||||||
 | 
					            throw new \Exception($this->connection->error);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function rollback(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!$this->connection->rollback() || !$this->connection->autocommit(true)) {
 | 
				
			||||||
 | 
					            throw new \Exception($this->connection->error);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function query(string $query): ?IResultSet
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!($result = $this->connection->query($query))) {
 | 
				
			||||||
 | 
					            throw new \Exception($this->connection->error . '. Query: ' . $query);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($result !== true) {
 | 
				
			||||||
 | 
					            return new ResultSet($result);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function multiQuery(string $query): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!$this->connection->multi_query($query)) {
 | 
				
			||||||
 | 
					            throw new \Exception($this->connection->error . '. Query: ' . $query);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $ret = [];
 | 
				
			||||||
 | 
					        do {
 | 
				
			||||||
 | 
					            if ($result = $this->connection->store_result()) {
 | 
				
			||||||
 | 
					                $ret[] = new ResultSet($result);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                $ret[] = null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->connection->more_results();
 | 
				
			||||||
 | 
					        } while ($this->connection->next_result());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->connection->error) {
 | 
				
			||||||
 | 
					            throw new \Exception($this->connection->error  . '. Query: ' . $query);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function prepare(string $query): IStatement
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!($stmt = $this->connection->prepare($query))) {
 | 
				
			||||||
 | 
					            throw new \Exception($this->connection->error . '. Query: ' . $query);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new Statement($stmt);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function lastId(): int
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->connection->insert_id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getAffectedRows(): int
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->connection->affected_rows;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										62
									
								
								src/Database/Mysql/ResultSet.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/Database/Mysql/ResultSet.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					<?php namespace MapGuesser\Database\Mysql;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use MapGuesser\Interfaces\Database\IResultSet;
 | 
				
			||||||
 | 
					use mysqli_result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ResultSet implements IResultSet
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private mysqli_result $result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(mysqli_result $result)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->result = $result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function fetch(int $type = IResultSet::FETCH_ASSOC)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->result->fetch_array($this->convertFetchType($type));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function fetchAll(int $type = IResultSet::FETCH_ASSOC)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->result->fetch_all($this->convertFetchType($type));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function fetchOneColumn(string $valueName, string $keyName = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $array = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while ($r = $this->fetch(IResultSet::FETCH_ASSOC)) {
 | 
				
			||||||
 | 
					            if (isset($keyName)) {
 | 
				
			||||||
 | 
					                $array[$r[$keyName]] = $r[$valueName];
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                $array[] = $r[$valueName];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $array;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function convertFetchType(int $type): int
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch ($type) {
 | 
				
			||||||
 | 
					            case IResultSet::FETCH_ASSOC:
 | 
				
			||||||
 | 
					                $internal_type = MYSQLI_ASSOC;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case IResultSet::FETCH_BOTH:
 | 
				
			||||||
 | 
					                $internal_type = MYSQLI_BOTH;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case IResultSet::FETCH_NUM:
 | 
				
			||||||
 | 
					                $internal_type = MYSQLI_NUM;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                $internal_type = MYSQLI_BOTH;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $internal_type;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										79
									
								
								src/Database/Mysql/Statement.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/Database/Mysql/Statement.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					<?php namespace MapGuesser\Database\Mysql;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use MapGuesser\Interfaces\Database\IResultSet;
 | 
				
			||||||
 | 
					use MapGuesser\Interfaces\Database\IStatement;
 | 
				
			||||||
 | 
					use mysqli_stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Statement implements IStatement
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private mysqli_stmt $stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(mysqli_stmt $stmt)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->stmt = $stmt;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __destruct()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->stmt->close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function execute(array $params = []): ?IResultSet
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($params) {
 | 
				
			||||||
 | 
					            $ref_params = [''];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach ($params as &$param) {
 | 
				
			||||||
 | 
					                $type = gettype($param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                switch ($type) {
 | 
				
			||||||
 | 
					                    case 'integer':
 | 
				
			||||||
 | 
					                    case 'double':
 | 
				
			||||||
 | 
					                    case 'string':
 | 
				
			||||||
 | 
					                        $t = $type[0];
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    case 'NULL':
 | 
				
			||||||
 | 
					                        $t = 's';
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    case 'boolean':
 | 
				
			||||||
 | 
					                        $param = (string) (int) $param;
 | 
				
			||||||
 | 
					                        $t = 's';
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    case 'array':
 | 
				
			||||||
 | 
					                        $param = json_encode($param);
 | 
				
			||||||
 | 
					                        $t = 's';
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!isset($t)) {
 | 
				
			||||||
 | 
					                    throw new \Exception('Data type ' . $type . ' not supported!');
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $ref_params[] = &$param;
 | 
				
			||||||
 | 
					                $ref_params[0] .= $t;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!call_user_func_array([$this->stmt, 'bind_param'], $ref_params)) {
 | 
				
			||||||
 | 
					                throw new \Exception($this->stmt->error);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!$this->stmt->execute()) {
 | 
				
			||||||
 | 
					            throw new \Exception($this->stmt->error);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($result_set = $this->stmt->get_result()) {
 | 
				
			||||||
 | 
					            return new ResultSet($result_set);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getAffectedRows(): int
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->stmt->affected_rows;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										157
									
								
								src/Database/Query/Modify.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										157
									
								
								src/Database/Query/Modify.php
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,157 @@
 | 
				
			|||||||
 | 
					<?php namespace MapGuesser\Database\Query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use MapGuesser\Interfaces\Database\IConnection;
 | 
				
			||||||
 | 
					use MapGuesser\Interfaces\Database\IResultSet;
 | 
				
			||||||
 | 
					use MapGuesser\Database\Utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Modify
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private IConnection $connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private string $table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private string $idName = 'id';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private array $attributes = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private array $original = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private bool $autoIncrement = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(IConnection $connection, string $table)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->connection = $connection;
 | 
				
			||||||
 | 
					        $this->table = $table;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setIdName(string $idName): Modify
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->idName = $idName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setAutoIncrement(bool $autoIncrement = true): Modify
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->autoIncrement = $autoIncrement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function fill(array $attributes): Modify
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->attributes = array_merge($this->attributes, $attributes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function set(string $name, $value): Modify
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->attributes[$name] = $value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setId($id): Modify
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->attributes[$this->idName] = $id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function save(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (isset($this->attributes[$this->idName])) {
 | 
				
			||||||
 | 
					            $this->update();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $this->insert();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function delete(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!isset($this->attributes[$this->idName])) {
 | 
				
			||||||
 | 
					            throw new \Exception('No primary key specified!');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $query = 'DELETE FROM ' . Utils::backtick($this->table) . ' WHERE ' . Utils::backtick($this->idName) . '=?';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $stmt = $this->connection->prepare($query);
 | 
				
			||||||
 | 
					        $stmt->execute([$this->idName => $this->attributes[$this->idName]]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function insert(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!$this->autoIncrement) {
 | 
				
			||||||
 | 
					            $this->attributes[$this->idName] = $this->generateKey();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $set = $this->generateColumnsWithBinding(array_keys($this->attributes));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $query = 'INSERT INTO ' . Utils::backtick($this->table) . ' SET ' . $set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $stmt = $this->connection->prepare($query);
 | 
				
			||||||
 | 
					        $stmt->execute($this->attributes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->autoIncrement) {
 | 
				
			||||||
 | 
					            $this->attributes[$this->idName] = $this->connection->lastId();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function update(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $diff = $this->generateDiff();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (count($diff) === 0) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $set = $this->generateColumnsWithBinding(array_keys($diff));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $query = 'UPDATE ' . Utils::backtick($this->table) . ' SET ' . $set . ' WHERE ' . Utils::backtick($this->idName) . '=?';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $stmt = $this->connection->prepare($query);
 | 
				
			||||||
 | 
					        $stmt->execute(array_merge($diff, [$this->idName => $this->attributes[$this->idName]]));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function readFromDB(array $columns): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $select = (new Select($this->connection, $this->table))
 | 
				
			||||||
 | 
					            ->setIdName($this->idName)
 | 
				
			||||||
 | 
					            ->whereId($this->attributes[$this->idName])
 | 
				
			||||||
 | 
					            ->columns($columns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->original = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateDiff(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->readFromDB(array_keys($this->attributes));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $diff = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($this->attributes as $name => $value) {
 | 
				
			||||||
 | 
					            $original = $this->original[$name];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($original != $value) {
 | 
				
			||||||
 | 
					                $diff[$name] = $value;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $diff;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static function generateColumnsWithBinding(array $columns): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        array_walk($columns, function(&$value, $key) {
 | 
				
			||||||
 | 
					            $value = Utils::backtick($value) . '=?';
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return implode(',', $columns);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateKey(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return substr(hash('sha256', serialize($this->attributes) . random_bytes(10) . microtime()), 0, 7);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										402
									
								
								src/Database/Query/Select.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										402
									
								
								src/Database/Query/Select.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,402 @@
 | 
				
			|||||||
 | 
					<?php namespace MapGuesser\Database\Query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Closure;
 | 
				
			||||||
 | 
					use MapGuesser\Interfaces\Database\IConnection;
 | 
				
			||||||
 | 
					use MapGuesser\Interfaces\Database\IResultSet;
 | 
				
			||||||
 | 
					use MapGuesser\Database\RawExpression;
 | 
				
			||||||
 | 
					use MapGuesser\Database\Utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Select
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const CONDITION_WHERE = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const CONDITION_HAVING = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private IConnection $connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private string $table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private string $idName = 'id';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private array $tableAliases = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private array $joins = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private array $columns = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private array $conditions = [self::CONDITION_WHERE => [], self::CONDITION_HAVING => []];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private array $groups = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private array $orders = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private array $limit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(IConnection $connection, string $table)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->connection = $connection;
 | 
				
			||||||
 | 
					        $this->table = $table;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setIdName(string $idName): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->idName = $idName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setTableAliases(array $tableAliases): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->tableAliases = array_merge($this->tableAliases, $tableAliases);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function columns(array $columns): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->columns = array_merge($this->columns, $columns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function innerJoin($table, $column1, string $relation, $column2): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->addJoin('INNER', $table, $column1, $relation, $column2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function leftJoin($table, $column1, string $relation, $column2): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->addJoin('LEFT', $table, $column1, $relation, $column2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function whereId($value): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->addWhereCondition('AND', $this->idName, '=', $value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function where($column, string $relation = null, $value = null): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->addWhereCondition('AND', $column, $relation, $value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function orWhere($column, string $relation = null, $value = null): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->addWhereCondition('OR', $column, $relation, $value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function having($column, string $relation = null, $value = null): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->addHavingCondition('AND', $column, $relation, $value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function orHaving($column, string $relation = null, $value = null): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->addHavingCondition('OR', $column, $relation, $value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function groupBy($column): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->groups[] = $column;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function orderBy($column, string $type = 'asc'): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->orders[] = [$column, $type];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function limit(int $limit, int $offset = 0): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->limit = [$limit, $offset];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function resetLimit(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->limit = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function paginate(int $page, int $itemsPerPage)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->limit($itemsPerPage, ($page - 1) * $itemsPerPage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function execute(): IResultSet
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        list($query, $params) = $this->generateQuery();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->connection->prepare($query)->execute($params);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function count(): int
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (count($this->groups) > 0 || count($this->conditions[self::CONDITION_HAVING]) > 0) {
 | 
				
			||||||
 | 
					            $orders = $this->orders;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->orders = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            list($query, $params) = $this->generateQuery();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $result = $this->connection->prepare('SELECT COUNT(*) num_rows FROM (' . $query . ') x')
 | 
				
			||||||
 | 
					                ->execute($params)
 | 
				
			||||||
 | 
					                ->fetch(IResultSet::FETCH_NUM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->orders = $orders;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return $result[0];
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $columns = $this->columns;
 | 
				
			||||||
 | 
					            $orders = $this->orders;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->columns = [new RawExpression('COUNT(*) num_rows')];
 | 
				
			||||||
 | 
					            $this->orders = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            list($query, $params) = $this->generateQuery();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $result = $this->connection->prepare($query)
 | 
				
			||||||
 | 
					                ->execute($params)
 | 
				
			||||||
 | 
					                ->fetch(IResultSet::FETCH_NUM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->columns = $columns;
 | 
				
			||||||
 | 
					            $this->orders = $orders;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return $result[0];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function addJoin(string $type, $table, $column1, string $relation, $column2): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->joins[] = [$type, $table, $column1, $relation, $column2];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function addWhereCondition(string $logic, $column, string $relation, $value): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->conditions[self::CONDITION_WHERE][] = [$logic, $column, $relation, $value];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function addHavingCondition(string $logic, $column, string $relation, $value): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->conditions[self::CONDITION_HAVING][] = [$logic, $column, $relation, $value];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateQuery(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $queryString = 'SELECT ' . $this->generateColumns() . ' FROM ' . $this->generateTable($this->table, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (count($this->joins) > 0) {
 | 
				
			||||||
 | 
					            $queryString .= ' ' . $this->generateJoins();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (count($this->conditions[self::CONDITION_WHERE]) > 0) {
 | 
				
			||||||
 | 
					            list($wheres, $whereParams) = $this->generateConditions(self::CONDITION_WHERE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $queryString .= ' WHERE ' .  $wheres;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $whereParams = [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (count($this->groups) > 0) {
 | 
				
			||||||
 | 
					            $queryString .= ' GROUP BY ' . $this->generateGroupBy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (count($this->conditions[self::CONDITION_HAVING]) > 0) {
 | 
				
			||||||
 | 
					            list($havings, $havingParams) = $this->generateConditions(self::CONDITION_HAVING);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $queryString .= ' HAVING ' .  $havings;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $havingParams = [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (count($this->orders) > 0) {
 | 
				
			||||||
 | 
					            $queryString .= ' ORDER BY ' . $this->generateOrderBy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (isset($this->limit)) {
 | 
				
			||||||
 | 
					            $queryString .= ' LIMIT ' . $this->limit[1] . ', ' . $this->limit[0];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return [$queryString, array_merge($whereParams, $havingParams)];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateTable($table, bool $defineAlias = false): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($table instanceof RawExpression) {
 | 
				
			||||||
 | 
					            return (string) $table;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (isset($this->tableAliases[$table])) {
 | 
				
			||||||
 | 
					            return ($defineAlias ? Utils::backtick($this->tableAliases[$table]) . ' ' . Utils::backtick($table) : Utils::backtick($table));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Utils::backtick($table);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateColumn($column): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($column instanceof RawExpression) {
 | 
				
			||||||
 | 
					            return (string) $column;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (is_array($column)) {
 | 
				
			||||||
 | 
					            $out = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($column[0]) {
 | 
				
			||||||
 | 
					                $out .= $this->generateTable($column[0]) . '.';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $out .= Utils::backtick($column[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!empty($column[2])) {
 | 
				
			||||||
 | 
					                $out .= ' ' . Utils::backtick($column[2]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return $out;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return Utils::backtick($column);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateColumns(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $columns = $this->columns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        array_walk($columns, function (&$value, $key) {
 | 
				
			||||||
 | 
					            $value = $this->generateColumn($value);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return implode(',', $columns);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateJoins(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $joins = $this->joins;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        array_walk($joins, function (&$value, $key) {
 | 
				
			||||||
 | 
					            $value = $value[0] . ' JOIN ' . $this->generateTable($value[1], true) . ' ON ' . $this->generateColumn($value[2]) . ' ' . $value[3] . ' ' . $this->generateColumn($value[4]);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return implode(' ', $joins);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateConditions(string $type): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $conditions = '';
 | 
				
			||||||
 | 
					        $params = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($this->conditions[$type] as $condition) {
 | 
				
			||||||
 | 
					            list($logic, $column, $relation, $value) = $condition;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($column instanceof Closure) {
 | 
				
			||||||
 | 
					                list($conditionsStringFragment, $paramsFragment) = $this->generateComplexConditionFragment($type, $column);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                list($conditionsStringFragment, $paramsFragment) = $this->generateConditionFragment($condition);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($conditions !== '') {
 | 
				
			||||||
 | 
					                $conditions .= ' ' . $logic . ' ';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $conditions .= $conditionsStringFragment;
 | 
				
			||||||
 | 
					            $params = array_merge($params, $paramsFragment);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return [$conditions, $params];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateConditionFragment(array $condition): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        list($logic, $column, $relation, $value) = $condition;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($column instanceof RawExpression) {
 | 
				
			||||||
 | 
					            return [(string) $column, []];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $conditionsString = $this->generateColumn($column) . ' ';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($value === null) {
 | 
				
			||||||
 | 
					            return [$conditionsString . ($relation == '=' ? 'IS NULL' : 'IS NOT NULL'), []];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $conditionsString .= strtoupper($relation) . ' ';;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch ($relation = strtolower($relation)) {
 | 
				
			||||||
 | 
					            case 'between':
 | 
				
			||||||
 | 
					                $params = [$value[0], $value[1]];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $conditionsString .= '? AND ?';
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case 'in':
 | 
				
			||||||
 | 
					            case 'not in':
 | 
				
			||||||
 | 
					                $params = $value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (count($value) > 0) {
 | 
				
			||||||
 | 
					                    $conditionsString .= '(' . implode(', ', array_fill(0, count($value), '?')) . ')';
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    $conditionsString = $relation == 'in' ? '0' : '1';
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                $params = [$value];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $conditionsString .= '?';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return [$conditionsString, $params];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateComplexConditionFragment(string $type, Closure $conditionCallback): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $instance = new static($this->connection, $this->table);
 | 
				
			||||||
 | 
					        $instance->tableAliases = $this->tableAliases;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $conditionCallback($instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        list($conditions, $params) = $instance->generateConditions($type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ['(' . $conditions . ')', $params];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateGroupBy(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $groups = $this->groups;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        array_walk($groups, function (&$value, $key) {
 | 
				
			||||||
 | 
					            $value = $this->generateColumn($value);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return implode(',', $groups);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function generateOrderBy(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $orders = $this->orders;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        array_walk($orders, function (&$value, $key) {
 | 
				
			||||||
 | 
					            $value = $this->generateColumn($value[0]) . ' ' . $value[1];
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return implode(',', $orders);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								src/Database/RawExpression.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/Database/RawExpression.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					<?php namespace MapGuesser\Database;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RawExpression
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private string $expression;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(string $expression)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->expression = $expression;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __toString(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->expression;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								src/Database/Utils.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Database/Utils.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					<?php namespace MapGuesser\Database;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Utils {
 | 
				
			||||||
 | 
					    public static function backtick(string $name) {
 | 
				
			||||||
 | 
					        return '`' . $name . '`';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/Interfaces/Database/IConnection.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/Interfaces/Database/IConnection.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					<?php namespace MapGuesser\Interfaces\Database;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IConnection
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function startTransaction(): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function commit(): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function rollback(): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function query(string $query): ?IResultSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function multiQuery(string $query): array;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function prepare(string $query): IStatement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function lastId(): int;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getAffectedRows(): int;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								src/Interfaces/Database/IResultSet.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/Interfaces/Database/IResultSet.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					<?php namespace MapGuesser\Interfaces\Database;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IResultSet
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const FETCH_ASSOC = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const FETCH_NUM = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const FETCH_BOTH = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function fetch(int $type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function fetchAll(int $type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function fetchOneColumn(string $valueName, string $keyName);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								src/Interfaces/Database/IStatement.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/Interfaces/Database/IStatement.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					<?php namespace MapGuesser\Interfaces\Database;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IStatement
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function execute(array $params): ?IResultSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getAffectedRows(): int;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user