Spec-Zone.ru › Phalcon 2

Микро-приложения

С помощью 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API