Единая точка входа (Front Controller) — шаблон проектирования
25 января 2020
Шаблон предлагает сделать для обработки входящих обращений единый начальный обработчик, который будет выполнять роль точки входа и распределительного центра. Это делается для того, чтобы запросы собирались централизованно в одном месте и уже от туда, в зависимости от типа обращения, перенаправлялись дальше каждый своему целевому обработчику.
Кроме того, паттерн позволяет упорядочить запросы, делает работу с ними удобной, снижает количество ошибок и ускоряет тестирование.
Код реализации паттерна на языке PHP и веб-сервере Apache. Скачать исходники (ZIP, 2 Кб)
Результат выполнения запроса на получение списка категорий /api/categories/
Результат выполнения запроса на получение сведений о товаре с ID = 1 /api/products/1/
Результат выполнения запроса на удаление товара с ID = 4 /api/products/4/
Кроме того, паттерн позволяет упорядочить запросы, делает работу с ними удобной, снижает количество ошибок и ускоряет тестирование.
Пример задачи: создать скрипт для обработки API-запросов.
Код реализации паттерна на языке PHP и веб-сервере Apache. Скачать исходники (ZIP, 2 Кб)

- Получение списка категорий
GET /api/categories/ - Получение категории с ID = 5
GET /api/categories/5/ - Удаление категории с ID = 5
DELETE /api/categories/5/ - Получение списка товаров
GET /api/products/ - Получение товара с ID = 1
GET /api/products/1/ - Удаление товара с ID = 3
DELETE /api/products/3/
.htaccess
Файл конфигурации сервера Apache, в котором выставлено перенаправление запросов из директории /api/ в файл /api/index.phpRewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
api.class.php
Содержит класс API для непосредственного выполнения API-методов. В классе имеются следующие методы:- getCategories() — возвращает список категорий;
- getCategory($id) — возвращает сведения о категории по заданному ID;
- deleteCategory($id) — удаляет категорию по заданному ID;
- getProducts() — возвращает список товаров;
- getProduct($id) — возвращает сведения о товаре по заданному ID;
- deleteProduct($id) — удаляет товар по заданному ID.
<?
/**
* Класс API
*/
class API
{
/**
* Категории товаров. В ключе элемента находится ID категории
* @var array
*/
private static $categories = array(
'1' => array(
'id' => '1',
'name' => 'Одежда'
),
'2' => array(
'id' => '2',
'name' => 'Книги'
),
'3' => array(
'id' => '3',
'name' => 'Электроника'
),
'4' => array(
'id' => '4',
'name' => 'Продукты питания'
),
'5' => array(
'id' => '5',
'name' => 'Косметика'
),
'6' => array(
'id' => '6',
'name' => 'Разное'
)
);
/**
* Товары. В ключе элемента находится ID товара
* @var array
*/
private static $products = array(
'1' => array(
'id' => '1',
'name' => 'Свитер вязанный'
),
'2' => array(
'id' => '2',
'name' => 'Пиджак'
),
'3' => array(
'id' => '3',
'name' => 'Джинсы'
),
'4' => array(
'id' => '4',
'name' => 'Макасины'
),
'5' => array(
'id' => '5',
'name' => 'Ботинки туристические'
),
'6' => array(
'id' => '6',
'name' => 'Футболка'
)
);
/**
* Возвращает список категорий
* @return array
*/
public static function getCategories()
{
return self::$categories;
}
/**
* Возвращает сведения о категории
* @param int $id - идентификатор (ID) категории
* @return array|bool - в случае успеха вернёт массив, а в случае ошибки вернёт 'false'
*/
public static function getCategory($id)
{
if (isset(self::$categories[$id])) {
return self::$categories[$id];
} else {
return false;
}
}
/**
* Удаляет категорию по заданному ID
* @param int $id - идентификатор (ID) категории
* @return bool - в случае успеха вернёт 'true', а в случае ошибки вернёт 'false'
*/
public static function deleteCategory($id)
{
if (isset(self::$categories[$id])) {
//Удаляем категорию
return true;
} else {
return false;
}
}
/**
* Возвращает список товаров
* @return array
*/
public static function getProducts()
{
return self::$products;
}
/**
* Возвращает сведения о товаре
* @param int $id - идентификатор (ID) товара
* @return array|bool - в случае успеха вернёт массив, а в случае ошибки вернёт 'false'
*/
public static function getProduct($id)
{
if (isset(self::$products[$id])) {
return self::$products[$id];
} else {
return false;
}
}
/**
* Удаляет товар по заданному ID
* @param int $id - идентификатор (ID) товара
* @return bool - в случае успеха вернёт 'true', а в случае ошибки вернёт 'false'
*/
public static function deleteProduct($id)
{
if (isset(self::$products[$id])) {
//Удаляем товар
return true;
} else {
return false;
}
}
}
?>
index.php
Содержит скрипт, обрабатывающий все входящие запросы к API. Обратите внимание, что для подготовки ответа на каждый вид запроса используется свой отдельный метод из класса API.<?
header('Content-Type: application/json');
//Подключаем класс для работы с API
require_once(__DIR__.'/api.class.php');
$return = array(
'status' => '',
'status_desc' => ''
);
$requestType = $_SERVER['REQUEST_METHOD'];
$requestPath = parse_url($_SERVER['REQUEST_URI']);
$requestPath = explode('/', trim($requestPath['path'], '/'));
//Метод API
$method = '';
if (isset($requestPath[1]) && $requestPath[1] != '') {
$method = trim($requestPath[1]);
}
//ID элемента
$elementId = '';
if (isset($requestPath[2]) && $requestPath[2] > 0) {
$elementId = (int)$requestPath[2];
}
if ($method !='') {
//КАТЕГОРИИ
if ($method == 'categories') {
if ($requestType == 'GET') {
//Получение списка категорий
if ($elementId === '') {
$return['categories'] = API::getCategories();
$return['status'] = 'success';
}
//Получение конкретной категории
else {
$return['category'] = API::getCategory($elementId);
if (is_array($return['category']) == true) {
$return['status'] = 'success';
} else {
$return['status'] = 'error';
$return['status_desc'] = 'Не удалось найти категорию с ID = '.$elementId;
}
}
} if ($requestType == 'DELETE') {
//Удаление категории
if ($elementId > 0) {
if (API::deleteCategory($elementId) == true) {
$return['status'] = 'success';
$return['status_desc'] = 'Категория с ID = '.$elementId.' удалена';
} else {
$return['status'] = 'error';
$return['status_desc'] = 'Не удалось удалить категорию с ID = '.$elementId;
}
}
}
}
//ТОВАРЫ
else if ($method == 'products') {
if ($requestType == 'GET') {
//Получение списка товаров
if ($elementId === '') {
$return['products'] = API::getProducts();
$return['status'] = 'success';
}
//Получение конкретного товара
else {
$return['product'] = API::getProduct($elementId);
if (is_array($return['product']) == true) {
$return['status'] = 'success';
} else {
$return['status'] = 'error';
$return['status_desc'] = 'Не удалось найти товар с ID = '.$elementId;
}
}
} if ($requestType == 'DELETE') {
//Удаление товара
if ($elementId > 0) {
if (API::deleteProduct($elementId) == true) {
$return['status'] = 'success';
$return['status_desc'] = 'Товар с ID = '.$elementId.' удалён';
} else {
$return['status'] = 'error';
$return['status_desc'] = 'Не удалось удалить товар с ID = '.$elementId;
}
}
}
}
//Ошибка. Указан недоступный метод
else {
$return['status'] = 'error';
$return['status_desc'] = 'Указан недоступный метод';
}
} else {
$return['status'] = 'error';
$return['status_desc'] = 'Не удалось определить метод API';
}
if ($return['status'] == '') {
$return['status'] = 'error';
$return['status_desc'] = 'По вашему запросу не удалось подобать нужный метод';
}
echo json_encode($return);
?>
Результат выполнения запроса на получение списка категорий /api/categories/
{
"status": "success",
"status_desc": "",
"categories": {
"1": {
"id": "1",
"name": "Одежда"
},
"2": {
"id": "2",
"name": "Книги"
},
"3": {
"id": "3",
"name": "Электроника"
},
"4": {
"id": "4",
"name": "Продукты питания"
},
"5": {
"id": "5",
"name": "Косметика"
},
"6": {
"id": "6",
"name": "Разное"
}
}
}
Результат выполнения запроса на получение сведений о товаре с ID = 1 /api/products/1/
{
"status": "success",
"status_desc": "",
"product": {
"id": "1",
"name": "Свитер вязанный"
}
}
Результат выполнения запроса на удаление товара с ID = 4 /api/products/4/
{
"status": "success",
"status_desc": "Товар с ID = 4 удалён"
}