Микро-приложения
С помощью Phalcon вы можете создавать приложения, подобные «микро-фреймворкам». Для этого вам нужно написать минимальное количество кода для создания приложения PHP. Микро-приложения подходят для реализации небольших приложений, API и прототипов практичным способом.
$app = new Phalcon\Mvc\Micro();
$app->get('/say/welcome/{name}', function ($name) {
echo "<h1>Welcome $name!</h1>";
});
$app->handle();
Создание микро-приложения
Phalcon\Mvc\Micro — это класс, отвечающий за реализацию микро-приложения.
$app = new Phalcon\Mvc\Micro();
Определение маршрутов
После создания объекта вам необходимо добавить некоторые маршруты. Phalcon\Mvc\Router управляет маршрутизацией внутри. Маршруты всегда должны начинаться с /. Ограничение по HTTP-методу необязательно при определении маршрутов, чтобы указать маршрутизатору сопоставлять только в том случае, если запрос также соответствует HTTP-методам. Следующий пример демонстрирует, как определить маршрут для метода GET:
$app->get('/say/hello/{name}', function ($name) {
echo "<h1>Hello! $name</h1>";
});
Метод «get» указывает, что связанный HTTP-метод — GET. Маршрут /say/hello/{name} также содержит параметр {$name}, который передаётся непосредственно обработчику маршрута (анонимной функции). Обработчики выполняются при совпадении маршрута. Обработчик может быть любым вызываемым элементом в среде PHP.
// With a function
function say_hello($name) {
echo "<h1>Hello! $name</h1>";
}
$app->get('/say/hello/{name}', "say_hello");
// With a static method
$app->get('/say/hello/{name}', "SomeClass::someSayMethod");
// With a method in an object
$myController = new MyController();
$app->get('/say/hello/{name}', array($myController, "someAction"));
//Anonymous function
$app->get('/say/hello/{name}', function ($name) {
echo "<h1>Hello! $name</h1>";
});
Phalcon\Mvc\Micro предоставляет набор методов для определения HTTP-метода (или методов), для которых ограничен маршрут:
//Matches if the HTTP method is GET
$app->get('/api/products', "get_products");
//Matches if the HTTP method is POST
$app->post('/api/products/add', "add_product");
//Matches if the HTTP method is PUT
$app->put('/api/products/update/{id}', "update_product");
//Matches if the HTTP method is DELETE
$app->delete('/api/products/remove/{id}', "delete_product");
//Matches if the HTTP method is OPTIONS
$app->options('/api/products/info/{id}', "info_product");
//Matches if the HTTP method is PATCH
$app->patch('/api/products/update/{id}', "info_product");
//Matches if the HTTP method is GET or POST
$app->map('/repos/store/refs',"action_product")->via(array('GET', 'POST'));
Маршруты с параметрами
Определение параметров в маршрутах очень просто, как показано выше. Название параметра должно быть заключено в скобки. Также доступно форматирование параметров с помощью регулярных выражений для обеспечения согласованности данных. Это показано в примере ниже:
//This route have two parameters and each of them have a format
$app->get('/posts/{year:[0-9]+}/{title:[a-zA-Z\-]+}', function ($year, $title) {
echo "<h1>Title: $title</h1>";
echo "<h2>Year: $year</h2>";
});
Маршрут начала
Обычно начальный маршрут в приложении — это маршрут /, и к нему чаще всего обращаются с помощью метода GET. Этот сценарий кодируется следующим образом:
//This is the start route
$app->get('/', function () {
echo "<h1>Welcome!</h1>";
});
Правила перенаправления
Следующие правила могут использоваться вместе с Apache для перенаправления URIS:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L]
</IfModule>
Работа с ответами
Вы можете создавать любые типы ответов в обработчике: напрямую создавать вывод, использовать движок шаблонов, включать представление, возвращать JSON и т. д.:
//Direct output
$app->get('/say/hello', function () {
echo "<h1>Hello! $name</h1>";
});
//Requiring another file
$app->get('/show/results', function () {
require 'views/results.php';
});
//Returning a JSON
$app->get('/get/some-json', function () {
echo json_encode(array("some", "important", "data"));
});
Кроме того, у вас есть доступ к сервису «response», с помощью которого можно лучше управлять ответом:
$app->get('/show/data', function () use ($app) {
//Set the Content-Type header
$app->response->setContentType('text/plain')->sendHeaders();
//Print a file
readfile("data.txt");
});
Или создать объект ответа и вернуть его из обработчика:
$app->get('/show/data', function () {
//Create a response
$response = new Phalcon\Http\Response();
//Set the Content-Type header
$response->setContentType('text/plain');
//Pass the content of a file
$response->setContent(file_get_contents("data.txt"));
//Return the response
return $response;
});
Перенаправления
Перенаправления могут выполняться для переадресации потока выполнения на другой маршрут:
//This route makes a redirection to another route
$app->post('/old/welcome', function () use ($app) {
$app->response->redirect("new/welcome")->sendHeaders();
});
$app->post('/new/welcome', function () use ($app) {
echo 'This is the new Welcome';
});
Генерация URL для маршрутов
Phalcon\Mvc\Url может использоваться для создания URL на основе определённых маршрутов. Вам нужно установить имя для маршрута; таким образом, сервис «url» может создать соответствующий URL:
//Set a route with the name "show-post"
$app->get('/blog/{year}/{title}', function ($year, $title) use ($app) {
//.. show the post here
})->setName('show-post');
//produce an URL somewhere
$app->get('/', function() use ($app) {
echo '<a href="', $app->url->get(array(
'for' => 'show-post',
'title' => 'php-is-a-great-framework',
'year' => 2012
)), '">Show the post</a>';
});
Взаимодействие с зависимостью инжектором
В микро-приложении контейнер сервисов Phalcon\DI\FactoryDefault создаётся неявно; кроме того, вы можете создать контейнер вне приложения для управления его сервисами:
use Phalcon\DI\FactoryDefault,
Phalcon\Mvc\Micro,
Phalcon\Config\Adapter\Ini as IniConfig;
$di = new FactoryDefault();
$di->set('config', function() {
return new IniConfig("config.ini");
});
$app = new Micro();
$app->setDI($di);
$app->get('/', function () use ($app) {
//Read a setting from the config
echo $app->config->app_name;
});
$app->post('/contact', function () use ($app) {
$app->flash->success('Yes!, the contact was made!');
});
Синтаксис массивов разрешён для лёгкого задания/получения сервисов в внутреннем контейнере сервисов:
use Phalcon\Mvc\Micro,
Phalcon\Db\Adapter\Pdo\Mysql as MysqlAdapter;
$app = new Micro();
//Setup the database service
$app['db'] = function() {
return new MysqlAdapter(array(
"host" => "localhost",
"username" => "root",
"password" => "secret",
"dbname" => "test_db"
));
};
$app->get('/blog', function () use ($app) {
$news = $app['db']->query('SELECT * FROM news');
foreach ($news as $new) {
echo $new->title;
}
});
Обработчик не найден
Когда пользователь пытается получить доступ к маршруту, который не определён, микро-приложение попытается выполнить обработчик «Не найден». Пример этого поведения приведён ниже:
$app->notFound(function () use ($app) {
$app->response->setStatusCode(404, "Not Found")->sendHeaders();
echo 'This is crazy, but this page was not found!';
});
Модели в микро-приложениях
Модели могут использоваться прозрачно в микро-приложениях, для загрузки моделей требуется только автозагрузчик:
$loader = new \Phalcon\Loader();
$loader->registerDirs(array(
__DIR__ . '/models/'
))->register();
$app = new \Phalcon\Mvc\Micro();
$app->get('/products/find', function(){
foreach (Products::find() as $product) {
echo $product->name, '<br>';
}
});
$app->handle();
События микро-приложения
Phalcon\Mvc\Micro может отправлять события в EventsManager (если он присутствует). События вызываются с типом «micro». Поддерживаются следующие события:
| Имя события | Вызвано | Прекратить операцию? |
|---|---|---|
| beforeHandleRoute | Вызывается основной метод, на данном этапе приложение не знает, есть ли сопоставленный маршрут | Да |
| beforeExecuteRoute | Маршрут сопоставлен, и он содержит допустимый обработчик, на данном этапе обработчик не был выполнен | Да |
| afterExecuteRoute | Вызывается после выполнения обработчика | Нет |
| beforeNotFound | Вызывается, когда ни один из определённых маршрутов не соответствует запрошенному URI | Да |
| afterHandleRoute | Вызывается после завершения всего процесса успешным образом | Да |
В следующем примере показано, как контролировать безопасность приложения с помощью событий:
use Phalcon\Mvc\Micro,
Phalcon\Events\Manager as EventsManager;
//Create a events manager
$eventManager = new EventsManager();
//Listen all the application events
$eventManager->attach('micro', function($event, $app) {
if ($event->getType() == 'beforeExecuteRoute') {
if ($app->session->get('auth') == false) {
$app->flashSession->error("The user isn't authenticated");
$app->response->redirect("/")->sendHeaders();
//Return (false) stop the operation
return false;
}
}
});
$app = new Micro();
//Bind the events manager to the app
$app->setEventsManager($eventManager);
События middleware
Помимо менеджера событий, события можно добавлять с помощью методов «before», «after» и «finish»:
$app = new Phalcon\Mvc\Micro();
//Executed before every route is executed
//Return false cancels the route execution
$app->before(function() use ($app) {
if ($app['session']->get('auth') == false) {
return false;
}
return true;
});
$app->map('/api/robots', function(){
return array(
'status' => 'OK'
);
});
$app->after(function() use ($app) {
//This is executed after the route was executed
echo json_encode($app->getReturnedValue());
});
$app->finish(function() use ($app) {
//This is executed when the request has been served
});
Вы можете вызывать эти методы несколько раз, чтобы добавить больше событий одного и того же типа:
$app->finish(function() use ($app) {
//First 'finish' middleware
});
$app->finish(function() use ($app) {
//Second 'finish' middleware
});
Код middleware можно повторно использовать, используя отдельные классы:
use Phalcon\Mvc\Micro\MiddlewareInterface;
/**
* CacheMiddleware
*
* Caches pages to reduce processing
*/
class CacheMiddleware implements MiddlewareInterface
{
public function call($application)
{
$cache = $application['cache'];
$router = $application['router'];
$key = preg_replace('/^[a-zA-Z0-9]/', '', $router->getRewriteUri());
//Check if the request is cached
if ($cache->exists($key)) {
echo $cache->get($key);
return false;
}
return true;
}
}
Затем добавьте экземпляр в приложение:
$app->before(new CacheMiddleware());
Доступны следующие события middleware:
| Имя события | Вызвано | Прекратить операцию? |
|---|---|---|
| before | Перед выполнением обработчика. Может использоваться для контроля доступа к приложению | Да |
| after | Выполняется после выполнения обработчика. Может использоваться для подготовки ответа | Нет |
| finish | Выполняется после отправки ответа. Может использоваться для выполнения очистки | Нет |
Использование контроллеров как обработчиков
Приложения среднего уровня, использующие подход Micro\MVC, могут потребовать организовать обработчики в контроллерах. Вы можете использовать Phalcon\Mvc\Micro\Collection для группировки обработчиков, которые относятся к контроллерам:
use Phalcon\Mvc\Micro\Collection as MicroCollection;
$posts = new MicroCollection();
//Set the main handler. ie. a controller instance
$posts->setHandler(new PostsController());
//Set a common prefix for all routes
$posts->setPrefix('/posts');
//Use the method 'index' in PostsController
$posts->get('/', 'index');
//Use the method 'show' in PostsController
$posts->get('/show/{slug}', 'show');
$app->mount($posts);
Контроллер «PostsController» может выглядеть так:
class PostsController extends Phalcon\Mvc\Controller
{
public function index()
{
//...
}
public function show($slug)
{
//...
}
}
В приведённом выше примере контроллер непосредственно инициализируется. Коллекция также имеет возможность ленивой загрузки контроллеров. Этот вариант обеспечивает лучшую производительность, загружая контроллеры только в том случае, если соответствующие маршруты сопоставляются:
$posts->setHandler('PostsController', true);
$posts->setHandler('Blog\Controllers\PostsController', true);
Возврат ответов
Обработчики могут возвращать сырые ответы, используя Phalcon\Http\Response или компонент, реализующий соответствующий интерфейс. При возврате ответов обработчиками они автоматически отправляются приложением.
use Phalcon\Mvc\Micro,
Phalcon\Http\Response;
$app = new Micro();
//Return a response
$app->get('/welcome/index', function() {
$response = new Response();
$response->setStatusCode(401, "Unauthorized");
$response->setContent("Access is not authorized");
return $response;
});
Вывод представлений
Phalcon\Mvc\View\Simple может использоваться для вывода представлений, следующий пример показывает, как это сделать:
$app = new Phalcon\Mvc\Micro();
$app['view'] = function() {
$view = new \Phalcon\Mvc\View\Simple();
$view->setViewsDir('app/views/');
return $view;
};
//Return a rendered view
$app->get('/products/show', function() use ($app) {
// Render app/views/products/show.phtml passing some variables
echo $app['view']->render('products/show', array(
'id' => 100,
'name' => 'Artichoke'
));
});
Связанные источники
- Создание простого REST API — это учебник, объясняющий, как создать микро-приложение для реализации RESTful веб-службы.
- Магазин наклеек — очень простое микро-приложение, использующее подход микро-MVC [Github].
© 2011–2016 Phalcon Framework Team
Licensed under the Creative Commons Attribution License 3.0.
https://docs.phalconphp.com/en/2.0.0/reference/micro.html