Статьи

Быстрое прототипирование приложений в PHP с использованием Micro Framework

Посмотрим правде в глаза: у всех нас есть отличные идеи для веб-приложения. Записываете ли вы их на бумаге или запоминаете, используя свою эйдетическую память, наступает момент, когда вы хотите проверить, является ли ваша идея действительно жизнеспособной.

В этом руководстве мы будем использовать микро-фреймворк, язык шаблонов и ORM для быстрой разработки прототипа приложения.


У всех нас было это чувство. Вы знаете, тот, где вы знаете, у вас есть отличная идея веб-приложения, только у вас нет времени, чтобы создать быстрый прототип и проверить идею, которая действительно будет работать. Используя микро-фреймворк, язык шаблонов и ORM, вы можете запустить его за считанные минуты.

В этом уроке мы будем использовать отличную микросреду Slim, язык шаблонов Twig и легкий свободный ORM Paris и Idiorm. Нашим примером приложения будет блог. Возможно, вы уже создали блог раньше, но мы здесь, чтобы узнать о микро-фреймворках, и блог отлично подходит для всех!

Первое, что вы хотите сделать, это получить эти пакеты с соответствующих веб-сайтов:

Теперь, когда у вас есть все пакеты, загруженные на ваш компьютер, пришло время настроить структуру каталогов. Мы будем помещать файлы в корневую папку нашего сайта, поэтому папка вашего проекта должна выглядеть так:

Наш прототип структуры каталогов

«Не забудьте включить файл .htaccess, который поставляется с Slim».

Теперь, когда наш проект структурирован, давайте удалим содержимое файла Slim index.php — мы напишем наш собственный чуть позже. Вы также можете TwigView.php все, кроме TwigView.php класса TwigView.php в пакете Slim extras.


Наш файл index.php будет выполнять функцию начальной загрузки, благодаря чему Slim, Twig, Paris и Idiorm будут прекрасно работать вместе. Slim перенаправит все запросы к нашему приложению здесь, проверив наличие подходящих шаблонов маршрутов и затем отправив соответствующий ответ. Этот файл в конечном итоге будет содержать всю нашу настройку приложения и логику.

Первое, что нам нужно сделать, это включить все библиотеки, которые сделают волшебство возможным. Добавьте следующее в файл начальной загрузки index.php :

1
2
3
4
5
6
7
8
<?php
// Slim
require ‘Slim/Slim.php’;
require ‘Views/TwigView.php’;
 
// Paris and Idiorm
require ‘Paris/idiorm.php’;
require ‘Paris/paris.php’;

Если все идет хорошо, запрос к вашему приложению не должен делать абсолютно ничего, и это здорово!

Теперь давайте запустим Twig. Используя пакет дополнений Slim, мы можем позволить Slim настроить среду Twig для нас. Все, что нужно знать, это каталог, в котором находится Twig, так что давайте добавим это в нашу загрузочную версию. Также создайте каталог шаблонов с именем templates в корне сайта, пока вы находитесь на нем.

1
2
// Configuration
TwigView::$twigDirectory = __DIR__ .

Следующий компонент в нашем стеке — это Paris и Idiorm, наш ORM. Он использует встроенный объект PHP PDO, поэтому вы можете использовать Postgres или SQLite для своего прототипа, но для этого урока мы будем использовать MySQL. Обязательно предоставьте ему соответствующие учетные данные базы данных:

1
2
3
ORM::configure(‘mysql:host=localhost;dbname=blog’);
ORM::configure(‘username’, ‘root’);
ORM::configure(‘password’, »);

Наконец, давайте наберем Slim и работаем. Это довольно сложно, я думаю, вы согласитесь:

1
2
3
4
// Start Slim.
$app = new Slim(array(
    ‘view’ => new TwigView
));

Слово предупреждения. Если вы попытаетесь запустить ваше приложение сейчас, вы можете получить загадочную ошибку. Не паникуйте! Мы решим это за мгновение, добавив несколько маршрутов.


Добавить маршруты в Slim просто. Все, что нужно знать Slim — это метод запроса маршрута (например, GET, POST, PUT и т. Д.) И URI для ответа и способ ответа. Сначала мы опишем основные маршруты нашего приложения, а затем в этом уроке создадим внутреннюю часть прототипа.

Давайте сначала создадим маршрут домашней страницы:

1
2
3
4
// Blog Home.
$app->get(‘/’, function() use ($app) {
 
});

Здесь мы говорим Slim ответить на любой запрос GET, указанный в корне нашего приложения. Последний параметр закрытия в конечном итоге будет содержать логику для генерации вывода страницы.

Давайте добавим еще один маршрут для просмотра отдельной статьи в блоге:

1
2
3
4
// Blog View.
$app->get(‘/view/(:id)’, function($id) use ($app) {
 
});

Обратите внимание на разницу здесь? В нашем параметре URI мы добавили slug (:id) , который говорит Slim ожидать значения в конце URI.

Если вы когда-либо использовали какой-либо другой фреймворк PHP, вы, вероятно, знакомы с этой концепцией. Если нет, наш пример будет соответствовать /view/1 , /view/2 и т. Д.

Мы также передали этот параметр в нашу функцию замыкания, чтобы мы могли использовать его и в логике приложения. Обратите внимание, как мы также передали переменную нашего приложения в область замыканий с use оператора use ? Это позволяет нам получить доступ к внутренним компонентам Slim, которые мы будем использовать для сбора данных запросов и получения ответов.

Наши маршруты администрирования должны будут использовать разные методы запросов, поэтому давайте добавим их в:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Admin Home.
$app->get(‘/admin’, function() use ($app) {
 
});
 
// Admin Add.
$app->get(‘/admin/add’, function() use ($app) {
 
});
 
// Admin Add — POST.
$app->post(‘/admin/add’, function() use ($app) {
 
});
 
// Admin Edit.
$app->get(‘/admin/edit/(:id)’, function($id) use ($app) {
 
});
 
// Admin Edit — POST.
$app->post(‘/admin/edit/(:id)’, function($id) use ($app) {
 
});
 
// Admin Delete.
$app->get(‘/admin/delete/(:id)’, function($id) use ($app) {
 
});

Вы заметите, что у нас здесь есть несколько POST-маршрутов. Позже мы будем использовать их для обработки форм в нашем административном центре.

Наконец, мы бы лучше сказали Slim запустить наше приложение.

1
$app->run();

Paris и Idiorm упрощают построение моделей для представления ваших данных, поскольку они выполняют большую часть трудоемкой работы, что отлично подходит для быстрого создания прототипов. Мы будем хранить наши модели в каталоге с именем models , поэтому давайте создадим этот каталог. Внутри него создайте базовую модель Article в файле Article.php :

1
2
3
4
5
<?php
class Article extends Model
{
 
}

Довольно просто, а? Paris и Idiorm извлекут всю необходимую информацию из имени класса модели и таблицы базы данных. Пока мы занимаемся этим, нам, вероятно, следует создать базу данных и добавить некоторые примеры данных:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
CREATE DATABASE `blog` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
 
USE `blog`;
 
CREATE TABLE IF NOT EXISTS `article` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `timestamp` datetime NOT NULL,
  `title` varchar(128) NOT NULL,
  `summary` varchar(128) NOT NULL,
  `content` text NOT NULL,
  `author` varchar(128) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
INSERT INTO `article` (`id`, `timestamp`, `title`, `summary`, `content`, `author`) VALUES
(1, ‘2011-07-28 02:03:14’, ‘Hello World!’, ‘Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut ‘, ‘Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.’, ‘Mr White’),
(2, ‘2011-07-28 02:03:14’, ‘More Hello World!’, ‘Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut ‘, ‘Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.’, ‘Mr Green’);

Наконец, поскольку мы будем использовать модель Article на каждой странице, мы включим ее в нашу загрузочную версию сразу после того, как мы загрузили наши библиотеки:

1
2
// Models
require ‘models/Article.php’;

Теперь, когда у нас есть все маршруты наших приложений и настроены наши модели, пришло время приступить к созданию нескольких страниц. Наш веб-интерфейс будет довольно простым, со списком всех статей блога и страницей для просмотра отдельных статей.

Используя свободно распространяемый интерфейс Paris и Idiorm, мы можем быстро создавать запросы к базе данных без написания необработанного SQL. Давайте вытянем все статьи для домашней страницы, используя закрытие маршрута:

1
$articles = Model::factory(‘Article’)->order_by_desc(‘timestamp’)->find_many();

Мы начнем с вызова метода фабрики моделей, который выдаст объект модели типа Article . Отсюда у нас есть свободный интерфейс, что означает, что мы можем объединить наши команды. Здесь мы получаем все статьи в базе данных, упорядоченные по метке времени, в порядке убывания, а затем сообщаем Парису, что мы хотим вернуть много статей. Результатом этого запроса является массив объектов модели Article.

Чтобы наши результаты отображались в браузере, нам нужно создать шаблон. Slim предоставляет простой метод визуализации, чтобы сделать это. Первый параметр — это шаблон для визуализации, а второй параметр — это ассоциативный массив данных, которые должны быть доступны для шаблона, который в нашем случае является объектами нашей статьи.

1
return $app->render(‘blog_home.html’, array(‘articles’ => $articles));

Мы будем писать наши шаблоны, используя Twig, который предоставляет чистую и простую структуру тегов с функциями наследования, которые мы можем использовать для простого размещения веб-страницы без использования PHP. Это отлично подходит для создания прототипов, так как это означает, что нужно сосредоточиться на формировании вывода страницы, а не пробираться через смешанный PHP и HTML-код спагетти.

Нам нужен базовый файл макета — layout.html базовый файл HTML в папке шаблонов с именем layout.html .

01
02
03
04
05
06
07
08
09
10
<!DOCTYPE html>
<html>
    <head>
        <title>{% block page_title %} {% endblock %}</title>
        <meta charset=&quot;utf8&quot;
    </head>
    <body>
        {% block content %} {% endblock %}
    </body>
</html>

Обратите внимание на теги блока Twig? Блоки — это именованные регионы, которые вы можете заполнить контентом. Мы заполним эти блоки в наших отдельных шаблонах страниц.

Вот краткий ускоренный курс по Twig, чтобы помочь вам.

Любая переменная или выражение в {{ }} автоматически экранируется и отображается, в то время как теги {% %} позволяют вам использовать операторы выполнения, такие как условные операторы else или для циклов.

Давайте шаг за шагом создадим шаблон домашней страницы блога. Не забудьте создать новый шаблон с именем blog_home.html в папке с шаблонами.

Первое, что мы хотим, чтобы наш шаблон — это расширение нашего макета. Тег extends позволяет Twig знать, что наш шаблон будет наследоваться от файла layout.html :

1
{% extends ‘layout.html’ %}

Теперь мы можем использовать тот же синтаксис блока, который мы использовали ранее, чтобы заполнить наш макет. Давайте установим заголовок страницы:

1
{% block page_title %}My Blog{% endblock %}

Twig заполнит область page_title в макете тем, что мы определили в нашем шаблоне. Чтобы проиллюстрировать возможности Twig, давайте создадим блок контента и воспользуемся еще несколькими функциями Twig:

1
2
3
4
5
6
7
{% block content %}
    {% for article in articles %}
         
    {% else %}
        <p>There are currently no articles.</p>
    {% endif %}
{% endblock %}

Помните, что мы передали наш полученный массив статей нашему шаблону ранее? Это теперь доступно в шаблоне с названием articles . Используя логические теги Twigs, мы перебираем переменную article, чтобы проверить, существует ли она, а если нет, выдают вежливое предупреждение. Мы объединяем цикл for и else условно в один набор тегов, чтобы легко обрабатывать пустой массив.

Давайте покажем список статей блога на главной странице, чтобы познакомиться с циклами Twig и синтаксисом вывода переменной:

1
2
3
4
5
6
7
8
{% block content %}
    {% for article in articles %}
        <h1><a href=&quot;/view/{{ article.id }}&quot;>{{ article.title }}</a> by {{ article.author }}</h1>
        <p>{{ article.summary }}</p>
    {% else %}
        <p>There are currently no articles.</p>
    {% endfor %}
{% endblock %}

Синтаксис цикла for является противоположностью PHP-оператора foreach — мы просто используем ключевое слово in вместо as . Это перебирает наш массив объектов article , делая каждый доступным как переменную под названием article внутри цикла.

Внутри цикла мы используем теги {{ }} , которые выводят экранированное значение. Да, Twig автоматически экранирует ваш вывод, так что больше не htmlentities() писать htmlentities() ! Мы также обращаемся к нашему атрибуту title статей с помощью точечной ( . ) Нотации вместо обычной стрелки PHP ( -> ). Если вы написали Javascript или Python, вы должны быть знакомы с некоторыми из этого синтаксиса.

Наш основной внешний вид домашней страницы

Теперь, когда у нас есть основная домашняя страница, давайте разберемся с этим подробным представлением.

1
2
3
4
5
6
7
8
9
// Blog View.
$app->get(‘/view/(:id)’, function($id) use ($app) {
    $article = Model::factory(‘Article’)->find_one($id);
    if (! $article instanceof Article) {
        $app->notFound();
    }
 
    return $app->render(‘blog_detail.html’, array(‘article’ => $article));
});

Используя Paris, мы можем быстро получить статью по ее идентификатору, используя метод find_one() . Если экземпляр объекта Article не возвращается, мы сообщаем приложению Slim, что страница не найдена, что автоматически вызовет ошибку 404.

Если статья найдена, мы передаем ее в наш подробный шаблон, который выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
{% extends &#x27;layout.html&#x27;
 
{% block page_title %}{{ article.title }}{% endblock %}
 
{% block content %}
    <h1>{{ article.title }}</h1>
    <p>Published: {{ article.timestamp|date(&#x27;jS F Y&#x27;) }} by {{ article.author }}</p>
    <p>{{ article.content }}</p>
    <p><a href=&quot;/&quot;>Back to Homepage</a></p>
{% endblock %}

Используя встроенные фильтры Twigs, мы можем получить доступ к некоторым основным функциям PHP, таким как date() в наших шаблонах. Атрибут класса article.timestamp автоматически передается нашему фильтру даты в качестве первого параметра, а наша строка формата даты становится вторым параметром.

Наш основной блог подробно

Теперь у нас есть работающий интерфейс, хотя и простой, но он не заставил себя долго ждать. Paris позволяет легко сосредоточиться на извлечении ваших данных из базы данных, и, как мы увидим при создании нашего центра администрирования, он также позволяет легко вставлять и обновлять записи.


Давайте поработаем над административным центром для нашего блога, который мы будем структурировать под URI /admin . Поскольку у нас уже есть все настройки маршрутов, давайте напишем логику для главной страницы административного центра. Он будет идентичен главной странице нашего блога, поэтому приведенный ниже код должен иметь полный смысл:

1
2
3
4
5
6
7
8
// Admin Home.
$app->get(&#x27;/admin&#x27;, function() use ($app) {
    $articles = Model::factory(&#x27;Article&#x27;)
                    ->order_by_desc(&#x27;timestamp&#x27;)
                    ->find_many();
 
    return $app->render(&#x27;admin_home.html&#x27;, array(&#x27;articles&#x27; => $articles));
});

Мы будем использовать простой макет таблицы с ссылками на действия для добавления, редактирования и удаления статей блога.

Вы уже знакомы с тем, как работает система блоков регионов в Twig, поэтому давайте просто сосредоточимся на нашем блоке контента:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{% block content %}
    <h1>My Blog Administration</h1>
 
    <p><a href=&quot;/admin/add&quot;>Add Article</a></p>
 
    {% if articles %}
        <table>
            <thead>
                <tr>
                    <th>Title</th>
                    <th>Date</th>
                    <th>Author</th>
                    <th colspan=&quot;2&quot;>Actions</th>
                </tr>
            </thead>
            <tbody>
 
                {% for article in articles %}
                    <tr>
                        <td>{{ article.title }}</td>
                        <td>{{ article.author }}</td>
                        <td>{{ article.timestamp|date(&#x27;jS F Y&#x27;) }}</td>
                        <td><a href=&quot;/admin/edit/{{ article.id }}&quot;>Edit</a></td>
                        <td><a href=&quot;/admin/delete/{{ article.id }}&quot;>Delete</a></td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    {% else %}
        <p>There are currently no articles.</p>
    {% endif %}
{% endblock %}

В этом шаблоне мы используем логику {% if %} {% else %} {% endif %} . Мы не хотим отображать нашу разметку таблицы, если нет статей, поэтому мы проверяем ее существование, прежде чем решить, что отображать. Мы также снова используем метод date filter , который, я думаю, вы согласитесь, довольно чистый и разборчивый.

Наша главная страница администратора

Давайте перейдем к реальному содержанию нашего админ-центра: манипулированию контентом. Нам нужна форма, которая содержит все поля, необходимые для добавления и редактирования нашей статьи. К счастью, Twig поддерживает партиалы многократного использования, поэтому давайте создадим article_form.html формы с именем article_form.html :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<form action=&quot;{{ action_url }}&quot;
    <h1>{{ action_name }} Article</h1>
 
    <p>
        <label for=&quot;title&quot;>Title: </label><br />
        <input type=&quot;text&quot;
    </p>
 
    <p>
        <label for=&quot;author&quot;>Author: </label><br />
        <input type=&quot;text&quot;
    </p>
 
    <p>
        <label for=&quot;summary&quot;>Summary: </label><br />
        <textarea name=&quot;summary&quot;
    </p>
 
    <p>
        <label for=&quot;content&quot;>Content: </label><br />
        <textarea name=&quot;content&quot;
    </p>
 
    <p>
        <input type=&quot;submit&quot;
    </p>
</form>

Частичное является просто повторно используемым шаблоном, оно может содержать стандартную логику Twig. В нашем шаблоне формы мы используем фильтр по default , который выводит значение по умолчанию, если фильтруемая переменная пуста или не существует. В случае наших полей формы мы выведем пустую строку, если ни один из атрибутов статьи не присутствует. Мы также ожидаем, что две переменные приведут нашу форму в рабочее состояние. Первый с именем action_name просто описывает действие формы для наших пользователей (т. action_url Добавляет или редактирует), а второй action_url используется в качестве действия формы.

Вы, несомненно, заметили, как логика для этой страницы разделена на два маршрута, один для GET и один для POST, что означает, что нам нужно написать функцию для обработки каждого метода. Наш маршрут GET просто должен отрисовать страницу — ничего сложного. Мы просто скажем Twig визуализировать новый шаблон:

1
2
3
4
// Admin Add.
$app->get(‘/admin/edit/(:id)’, function($id) {
    return $app->render(‘admin_input.html’, array(‘action_name’ => ‘Add’, ‘action_url’ => ‘/admin/add’));
});

Мы передаем две переменные, ожидаемые нашей частичной формой, в шаблон. Говоря об этом, позвольте мне объяснить, как использовать частичное в нашем шаблоне admin_input.html :

1
{% include ‘article_form.html’ %}

Я уверен, что вы, наверное, догадались, что это будет так просто, и это действительно так. Нам просто нужно включить частичное в одну из областей нашего блока Twig, и тогда оно появится. Он также будет иметь доступ ко всем переменным в пределах своего основного шаблона (т.е. две переменные, которые мы передали). Twig имеет несколько отличных элементов управления переменной области действия и функции безопасности песочницы, но их лучше сохранить на следующий день.

Наш окончательный шаблон ввода довольно прост (см. Ниже) и будет хорошо работать, когда мы также создадим наши элементы управления редактирования. Я полагаю, вы задаетесь вопросом, почему мы беспокоились о частичном в первой части, если и наши формы добавления и редактирования будут использовать один и тот же шаблон. Причина в том, что это делает повторное использование формы в другом месте во время создания прототипа настоящим делом, если это станет необходимым.

1
2
3
4
5
6
7
{% extends ‘layout.html’ %}
 
{% block page_title %}{{ action_name }} Article{% endblock %}
 
{% block content %}
    {% include ‘article_form.html’ %}
{% endblock %}
Наш админ добавляет страницу статьи

Давайте работать над этим маршрутом POST. Что нам нужно сделать, это получить опубликованные данные и сохранить их внутри объекта статьи. Мы не беспокоимся о проверке ошибок в нашем примере, так как мы всего лишь прототипируем нашу идею. Мы заставим Париж распределить или создать новый объект article :

1
$article = Model::factory(‘Article’)->create();

Теперь мы можем продолжить заполнение статьи из опубликованных данных. Мы получим данные POST из нашего объекта приложения Slim, который предоставляет удобный вспомогательный метод через объект запроса:

1
2
3
4
5
$article->title = $app->request()->post(‘title’);
$article->author = $app->request()->post(‘author’);
$article->summary = $app->request()->post(‘summary’);
$article->content = $app->request()->post(‘content’);
$article->timestamp = date(‘Ymd H:i:s’);

Париж заботится о том, чтобы при сбережении избежать всего нашего вклада, что удобно, если вы когда-нибудь решите подготовить свой прототип для доступа других. Все, что нам нужно сейчас сделать — это попросить Париж сохранить запись.

1
$article->save();

Наконец, мы говорим нашему приложению Slim, чтобы мы вернулись на главную страницу панели администратора с помощью метода redirect :

1
$app->redirect(‘/admin’);

На наш метод редактирования маршрута GET, который представляет собой просто объединение того, что мы узнали из создания страницы с подробностями нашего блога и страницы добавления администратора. Во-первых, нам нужно загрузить статью, которую мы редактируем, получив запись с Парижем:

1
2
3
4
$article = Model::factory(‘Article’)->find_one($id);
if (! $article instanceof Article) {
    $app->notFound();
}

Paris отправляет экземпляр объекта article, соответствующий идентификатору записи статьи, полученному в нашем закрытии, или false, если его не существует. Затем мы проверяем, вернули ли мы экземпляр, если нет, мы говорим Слиму выдать ошибку 404.

Теперь мы говорим Slim визуализировать шаблон ввода, как в нашем маршруте добавления, но передавая загруженный объект статьи и правильный URL-адрес действия:

1
2
3
4
5
return $app->render(‘admin_input.html’, array(
    ‘action_name’ => ‘Edit’,
    ‘action_url’ => ‘/admin/edit/’ .
    ‘article’ => $article
));

Наш маршрут редактирования POST работает почти так же, как и маршрут add , за исключением того, что нам нужно проверить, может ли статья быть загружена, прежде чем мы продолжим работу и обновим ее атрибуты:

01
02
03
04
05
06
07
08
09
10
11
12
13
$article = Model::factory(‘Article’)->find_one($id);
if (! $article instanceof Article) {
    $app->notFound();
}
 
$article->title = $app->request()->post(‘title’);
$article->author = $app->request()->post(‘author’);
$article->summary = $app->request()->post(‘summary’);
$article->content = $app->request()->post(‘content’);
$article->timestamp = date(‘Ymd H:i:s’);
$article->save();
 
$app->redirect(‘/admin’);

Мы завершим наш центр администрирования, построив маршрут удаления. Мы сделаем это, сначала извлекая запись, подобно тому, как мы делали это на странице с подробностями нашего блога ранее:

1
$article = Model::factory(‘Article’)->find_one($id);

Если Париж загрузил статью, нам нужно удалить ее, а затем отправить пользователя обратно на главную страницу администратора. Париж делает удаление записи настолько простым, насколько это возможно:

1
2
3
4
5
if ($article instanceof Article) {
    $article->delete();
}
 
$app->redirect(‘/admin’);

И с этим наш базовый прототип административного центра готов.


Наш админ-центр завершен. Это довольно просто, поскольку это всего лишь прототип, но мы все еще хотим, чтобы какая-то форма авторизации защищала его от посторонних глаз. Slim позволяет нам вставлять промежуточное ПО в наши маршруты. Это означает, что мы можем создавать функции, которые вызываются до того, как происходит закрытие ответа наших маршрутов.

Мы можем использовать HTTP Basic Auth для защиты нашего админцентра. Очевидно, что мы будем использовать что-то более безопасное на живом сайте, но для нашего прототипа это хорошо. В самом верху нашего index.php давайте создадим две константы, которые содержат наше имя пользователя и пароль:

1
2
3
// Auth Details.
define(‘USERNAME’, ‘admin’);
define(‘PASSWORD’, ‘password’);

После того, как мы создали наш экземпляр приложения Slim, мы создадим замыкание, которое мы свяжем с переменной, чтобы провести проверку промежуточного ПО авторизации:

1
2
3
4
// Auth Check.
$authCheck = function() use ($app) {
 
};

Если вы никогда раньше не использовали HTTP Basic Auth в PHP, это действительно просто. Мы можем использовать массив $_SERVER чтобы проверить, какие учетные данные были отправлены из веб-браузера пользователя, и сравнить их с нашими константами. Мы сделаем это в нашем недавно созданном закрытии. Первое, что нам нужно сделать в нашей функции проверки подлинности, это выяснить, были ли отправлены какие-либо учетные данные проверки подлинности, и, если они были, проверить, соответствуют ли они нашим константам:

1
2
3
$authRequest = isset($_SERVER[&#x27;PHP_AUTH_USER&#x27;], $_SERVER[&#x27;PHP_AUTH_PW&#x27;]);
$authUser = $authRequest &amp;&amp;
$authPass = $authRequest &amp;&amp;

Все, что мы здесь делаем, это проверяем, существуют ли и совпадают ли значения auth, затем сохраняем результаты в некоторых переменных. Предполагая, что любая из этих переменных является ложной, мы знаем, что нам нужно предложить пользователю авторизоваться:

1
2
3
4
5
6
7
if (! $authUser || ! $authPass) {
    $app->response()->header(&#x27;WWW-Authenticate: Basic realm=&quot;My Blog Administration&quot;&#x27;, &#x27;&#x27;);
    $app->response()->header(&#x27;HTTP/1.1 401 Unauthorized&#x27;, &#x27;&#x27;);
    $app->response()->body(&#x27;<h1>Please enter valid administration credentials</h1>&#x27;);
    $app->response()->send();
    exit;
}

Мы проверяем, в порядке ли наши аутентификационные данные. Если это не так, мы отправляем ответ с соответствующими заголовками и предупреждающим сообщением. Как вы видели ранее, мы могли получить доступ к объекту запроса Slim Framework, чтобы получить доступ к нашим данным POST. Мы также можем получить доступ к внутреннему объекту ответа, что позволяет нам легко вставлять заголовки и перезаписывать тело объекта ответа Slim простым HTML-предупреждением, прежде чем мы, наконец, заставим скрипт завершиться.

В Slim вы можете добавить несколько маршрутов к маршруту, и они выполняются в указанном порядке. Это означает, что мы можем легко предотвратить доступ ко всем нашим маршрутам, добавив закрытие проверки подлинности перед закрытием ответа:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Admin Home.
$app->get(‘/admin’, $authCheck, function() use ($app) {
    //…
});
 
// Admin Add.
$app->get(‘/admin/add’, $authCheck, function() use ($app) {
    //…
});
 
// Admin Add — POST.
$app->post(‘/admin/add’, $authCheck, function() use ($app) {
    //…
});
 
// Admin Edit.
$app->get(‘/admin/edit/(:id)’, $authCheck, function($id) use ($app) {
    //…
});
 
// Admin Edit — POST.
$app->post(‘/admin/edit/(:id)’, $authCheck, function($id) use ($app) {
    //…
});
 
// Admin Delete.
$app->get(‘/admin/delete/(:id)’, $authCheck, function($id) use ($app) {
    //…
});

И вот, наш админ-центр защищен. Любой, кто попытается получить к нему доступ, увидит предупреждающее сообщение и запросит свои учетные данные.

Вы должны дать мне некоторые полномочия, сэр!

Надеемся, что это руководство показало вам, насколько быстро и легко получить прототип и запустить его с помощью микро-фреймворка, ORM и языка шаблонов, сохраняя при этом хорошее разделение задач и читаемый код.

Мощный язык шаблонов может предотвратить превращение ваших представлений в нечитаемый код спагетти PHP и HTML, а также в то, как беглый ORM может сделать утомительные действия CRUD быстрыми и безболезненными.

Это лишь некоторые из множества интересных вещей, которые вы можете сделать со Slim, Twig и Paris. Если вы углубитесь в дальнейшие действия, вы можете добавить связи с вашими моделями в Paris, добавить фрагменты макросов в Twig, чтобы ускорить разработку шаблонов, и использовать маршрутизацию на основе имен с Slim, чтобы сделать связывание содержимого вашего веб-сайта и изменение URL-адресов тривиальным.

Удачного прототипирования и большое спасибо за чтение!