В предыдущей статье я начал изучать интеграцию между Drupal 7 и движком Elasticsearch . Цель состояла в том, чтобы увидеть, как мы можем объединить эти технологии с открытым исходным кодом для достижения высокопроизводительного приложения, которое использует лучшее из обоих миров. Если вы только что присоединились к нам, вы должны проверить этот репозиторий, который содержит соответствующий код для этих статей.
Теперь мы создадим небольшое приложение Silex, которое считывает данные прямо из Elasticsearch и возвращает их пользователю.
Приложение Silex
Silex — это отличный PHP-фреймворк, разработанный теми же людьми, которые стоят за проектом Symfony. На самом деле он использует в основном компоненты Symfony, но на более упрощенном уровне. Давайте посмотрим, как мы можем начать очень быстро с приложением Silex.
Есть несколько способов. Вы можете добавить его в качестве зависимости к существующему проекту на основе композитора:
"silex/silex": "~1.2",
Или вы можете даже создать новый проект, используя симпатичный маленький скелет, предоставленный создателем:
composer.phar create-project fabpot/silex-skeleton
Независимо от того, как настроен ваш проект, для доступа к Elasticsearch нам потребуется использовать его PHP SDK . Это должно быть добавлено в Composer:
"elasticsearch/elasticsearch": "~1.0",
И если мы хотим использовать Twig для вывода данных, нам это тоже понадобится (если, конечно, еще нет):
"symfony/twig-bridge": "~2.3"
Чтобы использовать SDK, мы можем представить его как сервис для Pimple , крошечного контейнера внедрения зависимостей Silex (гораздо проще, чем кажется). В зависимости от того, как настроен наш проект, мы можем сделать это в нескольких местах (см. Репозиторий для примера). Но в основном, после того, как мы создаем новое приложение Silex, мы можем добавить следующее:
$app['elasticsearch'] = function() {
return new Client(array());
};
Это создает новый сервис с именем elasticsearch
Client
И не забудьте, что нам нужно использовать этот класс вверху:
use Elasticsearch\Client;
Теперь, где бы мы ни хотели, мы можем получить клиента Elasticsearch, просто ссылаясь на это свойство в объекте $app
$client = $app['elasticsearch'];
Подключение к Elasticsearch
В предыдущей статье нам удалось получить данные нашего узла в индексе node
Так, например, это вернет все типы узлов статьи:
http://localhost:9200/node/article/_search
Мы также видели, как создать экземпляр клиента для нашего Elasticsearch SDK. Теперь пришло время использовать это как-то. Одним из способов является создание контроллера:
<?php
namespace Controller;
use Silex\Application;
use Symfony\Component\HttpFoundation\Response;
class NodeController {
/**
* Shows a listing of nodes.
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function index() {
return new Response('Here there should be a listing of nodes...');
}
/**
* Shows one node
*
* @param $nid
* @param \Silex\Application $app
* @return mixed
*/
public function show($nid, Application $app) {
$client = $app['elasticsearch'];
$params = array(
'index' => 'node',
'body' => array(
'query' => array(
'match' => array(
'nid' => $nid,
),
),
)
);
$result = $client->search($params);
if ($result && $result['hits']['total'] === 0) {
$app->abort(404, sprintf('Node %s does not exist.', $nid));
}
if ($result['hits']['total'] === 1) {
$node = $result['hits']['hits'];
return $app['twig']->render('node.html.twig', array('node' => reset($node)));
}
}
}
В зависимости от того, как вы организуете свое приложение Silex, этот класс контроллеров может быть в нескольких местах. В моем случае он находится в папке src/Controller
Нам также нужно создать маршрут, который сопоставляется с этим контроллером. Опять же, есть несколько разных способов справиться с этим, но в моем примере у меня есть файл routes.php
src/
index.php
<?php
use Symfony\Component\HttpFoundation\Response;
/**
* Error handler
*/
$app->error(function (\Exception $e, $code) {
switch ($code) {
case 404:
$message = $e->getMessage();
break;
default:
$message = 'We are sorry, but something went terribly wrong. ' . $e->getMessage();
}
return new Response($message);
});
/**
* Route for /node
*/
$app->get("/node", "Controller\\NodeController::index");
/**
* Route /node/{nid} where {nid} is a node id
*/
$app->get("/node/{nid}", "Controller\\NodeController::show");
Так что же происходит в моем примере выше? Во-первых, я определил обработчик ошибок для приложения, чтобы я мог видеть перехваченные исключения и выводить их на экран. Не так уж и важно. Затем я определил два маршрута, которые отображаются на два моих метода контроллера, определенных ранее. Но для краткости я лишь продемонстрировал, что может делать предполагаемый метод show()
- Получить клиент Elasticsearch
- Создайте параметры запроса Elasticsearch (аналогично тому, что мы делали в среде Drupal)
- Выполнить запрос
- Проверьте результаты и, если узел был найден, визуализируйте его с помощью шаблона Twig и передайте ему данные узла.
- Если результатов не найдено, прервите процесс с помощью 404, который вызывает наш обработчик ошибок для этого HTTP-кода, объявленного выше.
Если вы хотите следовать этому примеру, имейте в виду, что для использования Twig вам необходимо зарегистрировать его в своем приложении. Это не так сложно, если он уже есть в папке вашего поставщика через composer.
После создания экземпляра приложения Silex вы можете зарегистрировать провайдера:
$app->register(new TwigServiceProvider());
Убедитесь, что вы используете класс вверху:
use Silex\Provider\TwigServiceProvider;
И добавьте его как сервис с некоторой базовой конфигурацией:
$app['twig'] = $app->share($app->extend('twig', function ($twig, $app) {
return $twig;
}));
$app['twig.path'] = array(__DIR__.'/../templates');
Теперь вы можете создавать файлы шаблонов внутри папки templates/
Чтобы узнать больше о настройке приложения Silex, я рекомендую вам прочитать это введение в среду .
Чтобы продолжить наш пример контроллера, здесь у нас есть пара файлов шаблонов, которые выводят данные узла.
Внутри файла page.html.twig
<!DOCTYPE html>
<html>
<head>
{% block head %}
<title>{% block title %}{% endblock %} - My Elasticsearch Site</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
</body>
</html>
А внутри файла node.html.twig
{% extends "page.html.twig" %}
{% block title %}{{ node._source.title }}{% endblock %}
{% block content %}
<article>
<h1>{{ node._source.title }}</h1>
<div id="content">
{% if node._source.field_image %}
<div class="field-image">
{% for image in node._source.field_image %}
<img src="{{ image.url }}" alt="img.alt"/>
{% endfor %}
</div>
{% endif %}
{% if node._source.body %}
<div class="field-body">
{% for body in node._source.body %}
{{ body.value|striptags('<p><div><br><img><a>')|raw }}
{% endfor %}
</div>
{% endif %}
</div>
</article>
{% endblock %}
Это всего лишь некоторые базовые шаблоны для печати данных нашего узла в браузере (иначе это не так весело). У нас есть базовый файл и один, который расширяет его и выводит заголовок узла, изображения и основной текст на экран.
Кроме того, вы также можете вернуть JSON-ответ от вашего контроллера с помощью класса JsonResponse
use Symfony\Component\HttpFoundation\JsonResponse;
А из вашего контроллера просто верните новый экземпляр со значениями, переданными ему:
return new JsonResponse($node);
Вы можете легко создать такой API. Но сейчас это уже должно работать. При указании вашего браузера на http://localhost/node/5
С одной большой разницей: это намного намного быстрее. Здесь нет начальной загрузки, слоя тем, запросов к базе данных и т. Д. С другой стороны, у вас нет ничего полезного, кроме того, что вы создаете сами, используя компоненты Silex / Symfony. Это может быть хорошо или плохо в зависимости от типа проекта, над которым вы работаете. Но дело в том, что у вас есть возможность нарисовать некоторые линии для этой интеграции и решить ее степень.
Одним из концов спектра может быть создание всего вашего внешнего интерфейса с помощью Twig или даже Angular.js с Silex в качестве бэкэнда API. Другой — использовать Silex / Elasticsearch для одной страницы Drupal и использовать его только для лучшего поиска контента. Где-то посередине, вероятно, будет использоваться такое решение для всего раздела сайта Drupal, который посвящен взаимодействию с тяжелыми данными (например, видеомагазином или чем-то еще). Тебе решать.
Вывод
В этой статье мы увидели, как быстро настроить приложение Silex и использовать его для возврата некоторых данных из Elasticsearch. Цель состояла не столько в том, чтобы узнать, как работает любая из этих технологий, сколько в том, чтобы изучить варианты их интеграции. Отправной точкой стал веб-сайт Drupal, который может выступать в качестве идеальной системы управления контентом, которая масштабируется при правильном построении. Управляемые там данные могут быть выгружены в высокопроизводительное хранилище данных на основе Elasticsearch и снова извлечены для конечных пользователей с помощью Silex, простой и быстрой среды PHP.