Created
December 15, 2017 11:35
-
-
Save stevenpray/b46e3e62effe4b440823f39de2b8a889 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
ini_set('html_errors', 'false'); | |
error_reporting(E_ALL | E_STRICT); | |
set_exception_handler('error'); | |
define('DB_HOST', '127.0.0.1'); | |
define('DB_USER', 'root'); | |
define('DB_PASS', null); | |
define('DB_NAME', 'untitled'); | |
/** | |
* Response handler. | |
* | |
* @param int $status | |
* @param mixed $data | |
*/ | |
function respond(int $status, $data = null): void | |
{ | |
http_response_code($status); | |
header('Content-Type: application/json'); | |
if ($data !== null) { | |
echo json_encode($data, JSON_PRETTY_PRINT); | |
} | |
die; | |
} | |
/** | |
* Catch-all error handler. | |
* | |
* @param Throwable $throwable | |
*/ | |
function error(Throwable $throwable): void | |
{ | |
respond(500, $throwable->getMessage()); | |
} | |
$pdo = new PDO( | |
sprintf('mysql:host=%s;dbname=%s', DB_HOST, DB_NAME), | |
DB_USER, | |
DB_PASS, | |
[ | |
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, | |
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, | |
] | |
); | |
/** | |
* Fetch company entity with embedded company_addresses. | |
* | |
* @param PDO $pdo | |
* @param int $id | |
* @return array | |
*/ | |
function fetch_company(PDO $pdo, int $id = null): array | |
{ | |
$sql = 'SELECT * FROM company'; | |
if ($id !== null) { | |
$sql = 'SELECT * FROM company WHERE company.id = :id'; | |
} | |
$statement = $pdo->prepare($sql); | |
$statement->bindParam(':id', $id, PDO::PARAM_INT); | |
$statement->execute(); | |
$result = []; | |
while ($row = $statement->fetch()) { | |
$sql = 'SELECT * FROM company_address WHERE company_address.company_id = :id'; | |
$statement2 = $pdo->prepare($sql); | |
$statement2->bindParam(':id', $row['id'], PDO::PARAM_INT); | |
$statement2->execute(); | |
$row['addresses'] = $statement2->fetchAll(); | |
$result[] = $row; | |
} | |
return $result; | |
} | |
// Parse request body. | |
$data = json_decode(file_get_contents('php://input'), true); | |
// Controllers. | |
$routes = [ | |
'/^\/$/' => [ | |
'GET' => function () use ($pdo) { | |
respond(200, fetch_company($pdo)); | |
}, | |
'POST' => function () use ($pdo, $data) { | |
$sql = 'INSERT INTO company (name, description) VALUES (:name, :description)'; | |
$statement = $pdo->prepare($sql); | |
$statement->bindParam(':name', $data['name']); | |
$statement->bindParam(':description', $data['description']); | |
$statement->execute(); | |
$id = (int)$pdo->lastInsertId(); | |
$sql = 'INSERT INTO company_address (company_id, address, address_2, city, state, zip) VALUES (:company_id, :address, :address_2, :city, :state, :zip)'; | |
$statement = $pdo->prepare($sql); | |
$statement->bindParam(':company_id', $id, PDO::PARAM_INT); | |
$statement->bindParam(':address', $data['address']); | |
$statement->bindParam(':address_2', $data['address_2']); | |
$statement->bindParam(':city', $data['city']); | |
$statement->bindParam(':state', $data['state']); | |
$statement->bindParam(':zip', $data['zip']); | |
$statement->execute(); | |
$pdo->commit(); | |
respond(201, fetch_company($pdo, $id)); | |
}, | |
], | |
'/^\/[0-9]+$/' => [ | |
'GET' => function (int $id) use ($pdo) { | |
respond(200, fetch_company($pdo, $id)); | |
}, | |
'DELETE' => function (int $id) use ($pdo) { | |
$statement = $pdo->prepare('DELETE FROM company WHERE id = :id'); | |
$statement->bindParam(':id', $id, PDO::PARAM_INT); | |
$statement->execute(); | |
$pdo->commit(); | |
respond(200, 'Deleted.'); | |
}, | |
'PUT' => function (int $id) use ($pdo, $data) { | |
$table_fields = [ | |
'company' => ['name', 'description'], | |
'company_address' => ['address', 'address_2', 'city', 'state', 'zip'], | |
]; | |
$params = []; | |
/** @var string[] $fields */ | |
foreach ($table_fields as $table => $fields) { | |
foreach ($fields as $field) { | |
if (array_key_exists($field, $data)) { | |
$params[$field] = sprintf('%1$s.%2$s = :%2$s', $table, $field); | |
} | |
} | |
} | |
$sql = sprintf('UPDATE company LEFT JOIN company_address ON (company.id = company_address.company_id) SET %s WHERE (company.id = :id)', implode(', ', $params)); | |
$statement = $pdo->prepare($sql); | |
foreach ($params as $field => $param) { | |
$statement->bindParam(':'.$field, $data[$field]); | |
} | |
$statement->bindParam(':id', $id, PDO::PARAM_INT); | |
$statement->execute(); | |
$pdo->commit(); | |
respond(200, fetch_company($pdo, $id)); | |
}, | |
], | |
]; | |
// Router. | |
//['REQUEST_URI' => $uri, 'REQUEST_METHOD' => $method] = $_SERVER | |
/** @var callable[] $route */ | |
foreach ($routes as $uri => $route) { | |
if (preg_match($uri, $_SERVER['REQUEST_URI'], $matches)) { | |
foreach ($route as $method => $controller) { | |
if ($method === $_SERVER['REQUEST_METHOD']) { | |
$id = null; | |
if (count($matches) > 1) { | |
$id = (int)ltrim(array_shift($matches), '/'); | |
} | |
if ($id) { | |
$sql = 'SELECT id FROM company WHERE id = :id'; | |
$statement = $pdo->prepare($sql); | |
$statement->bindParam(':id', $id); | |
$statement->execute(); | |
if ($statement->fetch() === false) { | |
respond(404); | |
} | |
} | |
try { | |
$pdo->beginTransaction(); | |
$controller($id); | |
} catch (PDOException $exception) { | |
$pdo->rollBack(); | |
if ($exception->getCode() === '23000') { | |
respond(422, $exception->getMessage()); | |
} | |
throw $exception; | |
} | |
} | |
} | |
respond(405); | |
} | |
} | |
respond(404); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment