<?php
bootstrap();
function bootstrap()
{
// Инициализируем всё.
$users = new UserStore();
$userCarts = new UserCartStore();
$products = new ProductStore();
$controller = new CartController(
$users,
$userCarts,
$products
);
$httpHandler = new HttpCartHandler(
$controller
);
$router = new Router();
// Настраиваем роутер.
$router->onNothing(static function () {
print 'Unexpected route';
});
$router->addRoute('/cart/add', static function () use ($httpHandler) {
$httpHandler->addProductToCart();
});
// Запускаем роутер, он вызовет хендлер, тот контроллер, а тот базы данных.
$router->route($_SERVER['REQUEST_URI']); // REQUEST_URI - это не совсем то, я для примера написал.
}
class Router
{
protected $routes = [];
protected $onNothing;
public function addRoute($path, callable $callback)
{
$this->routes[$path] = $callback;
}
public function onNothing(callable $callback)
{
$this->onNothing = $callback;
}
public function route($path)
{
if (!empty($this->routes[$path])) { $this->routes[$path]();
} elseif (!empty($this->onNothing)) { ($this->onNothing)();
} else {
throw new Exception('No "nothing" callback was configured');
}
}
}
class HttpCartHandler
{
/** @var CartController */
protected $cartController;
public function __construct(CartController $cartController)
{
$this->cartController = $cartController;
}
public function addProductToCart()
{
$userId = $_POST['user_id'] ?? null;
$productId = $_POST['product_id'] ?? null;
try {
$this->cartController->addProductToCart(
$userId,
$productId
);
print 'Successfully added'; // Для принтов по идее нужен отдельный класс-Renderer;
} catch (InvalidArgumentException $e) {
print 'Invalid argument: ' . $e->getMessage();
} catch (\Throwable $e) {
print 'Internal error';
}
}
}
class CartController
{
// В реальном коде тут были бы интерфейсы, я же пока захардкодил сразу классы.
/** @var UserStore */
protected $users;
/** @var UserCartStore */
protected $userCarts;
/** @var ProductStore */
protected $products;
/**
* @param UserStore $users
* @param UserCartStore $userCarts
* @param ProductStore $products
*/
public function __construct($users, $userCarts, $products)
{
$this->users = $users;
$this->userCarts = $userCarts;
$this->products = $products;
}
public function addProductToCart($userId, $productId)
{
$user = $this->users->load($userId);
if ($user === null) {
throw new InvalidArgumentException('invalid user id');
}
$product = $this->products->load($productId);
if ($product === null) {
throw new InvalidArgumentException('invalid product id');
}
$this->userCarts->addProduct($userId, $productId);
}
}
class UserCartStore
{
public function addProduct($userId, $productId)
{
}
}
class UserStore
{
public function load($userId)
{
}
}
class ProductStore
{
public function load($productId)
{
}
}