Честно говоря, не думал, что только знакомство с системой затянется аж на 10 заметок. Мне-то оно всё давно привычно и понятно, а вот когда пытаешься внятно об этом рассказать...
В общем, сегодня мы заканчиваем вводную часть, и дальше будет настоящая работа по постройке магазина VespShop.
На нужно посмотреть, какие еще компоненты я написал для удобной работы на Vesp, и начнём с переключателя языка - vesp-change-locale
(по клику откроется GIFка)
Следующий важный компонент админки - модальные окна для создания и редактирования моделей.
Vesp-modal
расширяет компонент из BootstrapVue, принимает всего его параметры и добавляет отправку формы с данными.
Редактируемые данные передаются через v-model
, и если в них указан первичный ключ (по умолчанию поле id
, но можно настроить и другой), то форма отправится методом PATCH
(редактирование), а если нет, то PUT
(создание).
Содержимое формы вставляется в слот #form-fields
, а сами формы я предлагаю хранить отдельно от модальных окон, для удобства. Давайте разберём форму работы с пользователями.
Продолжаем наше знакомство с админкой Vesp.
Опираясь на свой опыт работы в MODX я постарался повторить примерную логику работы и здесь, для чего были написаны основные компоненты админки. Под капотом они используют BootstrapVue, но в будущем могут быть переписаны и на другую систему, при этом основной код страниц менять не придётся.
Для примера давайте разберёмся как именно работает раздел с пользователями
Сегодня мы начинаем знакомиться с админкой нашего приложения. Напоминаю, это точно такое же приложение, как и site
, только не в минимальной комплектации, а со всеми нужными модулями по умолчанию.
Работает оно с помощью компонентов Booststrap-Vue, и и к его документации мы будем обращаться очень часто. Для оформления внешнего вида мы подключаем стили из Bootstrap.
Первом делом мы видим форму авторизации, которая работает при помощи модуля @nuxtjs/auth. Все модули подключаются в frontend/src/admin/nuxt.config.js
, добавлением в Config.modules
или Config.buildModules
- это зависит от самого модуля и авторы пишут куда именно их нужно добавлять.
Этот модуль добавляет нам в приложение объект $auth
, к которому можно обращаться из любого компонента. Если посмотреть в основной шаблон админки admin/layouts/default.vue
, то вы увидите как именно выводится форма авторизации:
Как вы уже поняли по предыдущим заметкам, бэкенд и фронтенд Vesp не зависят друг от друга вообще никак. На прошлом занятии мы отправляли запросы в API из консоли через cURL и всё нормально работало.
Вместо консоли это могло быть и мобильное приложение, и любой веб-сайт. Я же предлагаю использовать веб-приложение, написанное на VueJS, с использованием NuxtJS - потому что они мне очень нравятся. И сейчас расскажу, почему.
Как мы уже выяснили в прошлой заметке, пользователь авторизовывается в контроллерах при каждем запросе с помощью токена JWT, который передаётся или в заголовках, или в GET параметре, или получается из куки.
Теперь давайте посмотрим, как происходит получение этого токена пользователем.
Согласно нашему route.php
запросы на авторизацию принимаются по адресу api/security/login
контроллером App\Controllers\Security\Login
, который расширяет Vesp\Controllers\Security\Login
:
<?php
// Это оригинальный контроллер из vesp/core
namespace Vesp\Controllers\Security;
use Psr\Http\Message\ResponseInterface;
use Vesp\Controllers\Controller;
use Vesp\Helpers\Jwt;
use Vesp\Models\User;
class Login extends Controller
{
// Контроллер работает с моделью User
protected $model = User::class;
// Обращаться можно только методом POST
public function post(): ResponseInterface
{
// для авторизации требуются username и password
$username = trim($this->getProperty('username', ''));
$password = trim($this->getProperty('password', ''));
// Выбираем пользователя по username
$user = (new $this->model())->newQuery()->where('username', $username)->first();
// Если есть такой, и указан верный пароль
if ($user && $user->verifyPassword($password)) {
// Проверяем его статус, и возвращаем токен, или ошибку
return !$user->active
? $this->failure('This user is not active', 403)
: $this->success(['token' => Jwt::makeToken($user->id)]);
}
// Авторизовать не удалось - возвращаем ошибку
return $this->failure('Wrong username or password');
}
}
Мы продолжаем знакомиться с внутренним устройством Vesp и сегодня пришла пора поговорить о системе прав доступа к данным.
После работы с MODX мне не хотелось изобретать что-то сложное, поэтому я придумал следующее:
scope
(область действия)users
позволяет любые запросы, то users/get
только получение данных, без put
, patch
и delete
.Таким образом каждой группе можно гибко давать разрешения на конкретные методы в контроллерах.
Когда подобной системы недостаточно, и нужно проверять, например, id
автора комментария при редактировании, то мы просто расширяем метод checkScope
у контроллера.
Давайте посмотрим, как он работает по-умолчанию.
На прошлых уроках мы работали с миграциями Phinx и моделями Eloquent - это всё сторонние библиотеки, а где же сам Vesp?
А он в контроллерах, которые были написаны под сильным впечатлением от процессоров MODX, и работают через Slim 4. Интересный факт - MODX 3 в своё время планировали завязать именно на Slim, но что-то пошло не так, и эти планы забросили.
Итак, все запросы от пользователей приходят в один-единственный коннектор www/api.php
. Он подключает всё нужное файлом core/bootstrap.php
(который можно использовать во всяких консольных скриптах) и создаёт экземпляр приложения Slim.
Дальше в это приложение грузятся наши маршруты из файла core/routes.php
, и теперь система знает, какой контроллер отвечает за конкретный запрос. Давайте разберёмся с маршрутами.
Сегодня посмотрим как работать с нашими новыми таблицами, созданными в прошлом уроке.
Модели - это PHP классы, лежащие в core/src/Models
, расширяющие Illuminate\Database\Eloquent\Model
и представляющие собой записи в соответствующей таблице базы данных. В отличие от MODX и его xDPO, здесь не нужно писать никаких схем и генерировать непонятные map
файлы. Одна модель - это всегда один класс и одна таблица в БД, всё очень просто и понятно. Если миграции меняют таблицу, то эти изменения нужно будет отразить и в модели.
Vesp устанавливает 4 модели по умолчанию: File
, UserRole
, User
, UserToken
- они отражают записи в таблицах files
, user_roles
, users
и user_tokens
соответственно.
Как видно, имена моделей чётко соотносятся с таблицами согласно правилам английского языка - и это не случайно. В Eloquent приняты определённые соглашения по многим ключевым моментам, включая имена моделей и таблиц.
На прошлом уроке мы дошли до запуска проекта со стандартными таблицами и данными, теперь давайте разберёмся, откуда они взялись.
В директории core/db
есть 2 поддиректории: migrations
и seeds
. В первой, понятно, миграции, а во второй скрипты для "засеивания" начальных данных. Для работы используется Phinx, конфигурация которого хранится в core/phinx.php
- там нам ничего менять не нужно, все настройки берутся из настроек окружения .env
.
Миграциями называют изменение структуры базы данных без потери её консистентности. Каждая миграция может быть отменена, при этом она возвращает структуру БД к предыдущему виду. На продакшене, конечно же, никто миграции не откатывает - это нужно только на время разработки.
Для запуска миграций в Vesp мы используем команду composer db:migrate
, для отката composer db:rollback
.
Теперь давайте посмотрим на сами файлы миграций.
Первым делом нам нужно разобраться с вашей рабочей средой. Я использую одни из самых популярных инструментов:
Здесь нет ничего особенного, обычный набор веб-разработчика.
Если вы используете такой же сетап, то поздравляю, вам будет максимально легко следовать моим инструкциям - нужно только установить специальный драйвер для Valet из репозитория vesp-valet-driver, что делается простым копированием файла VespValetDriver.php
в ~/.config/valet/Drivers
.
Структурно Vesp состоит из 2х больших частей: фронтенда на VueJS и бэкенда на PHP. Обе части разрабатываются (и могут быть использованы) независимо друг от друга и хранятся в разных репозиториях:
Объединяются они в 1 общем пакете, который называется просто Vesp и ставится из Packagist при помощи composer. Давайте создадим наш новый проект VespShop.
composer create-project vesp/vesp ./VespShop
Команда create-project
у composer не просто скачивает пакеты, но и запускает скрипты, прописанные в composer.json. В нашем случае они устанавливают зависимости Node.js.
Далее заходим в директорию VespShop
и делаем valet link vesp-shop
, что создаёт в нашем Valet новый сайт vesp-shop.test
.
В нём пока ничего нет, поэтому делаем в той же директории composer node:generate
и переходим по локальному адресу http://vesp-shop.test - теперь вы должны увидеть такую картинку:
Давайте разберёмся как это всё работает.
Примерно с 2020 года я работаю на своём собственном фреймворке Vesp, который мне очень нравится. Он простой, быстрый, построен на известных популярных решениях и не ограничивает разработчика.
Именно на Vesp построен и сам сайт bezumkin.ru.
Основное отличие заключается в полном разделении бэкенда и фронтенда, что превращает мой сайты уже в веб-приложения, когда отдельно работает API, а интерфейс отправляет в него запросы.
Такое устройство делает работу сервиса очень понятной и прозрачной, и заодно позволяет подключать к API мобильные приложения, или другие сайты для получения данных. Можно делать запросы в API и вовсе без интерфейса, что я в дальнейшем и продемонструрую.
А еще такие сайты очень удобно разрабатывать и отлаживать, весь код хранится в файлах, можно использовать xDebug и всякие другие DevTools. Прибавте сюда огромную массу готовых для интеграции библиотек на NpmJs и Packagist.
В общем, после работы с MODX, это просто совершенно другой, гораздо более современный и удобный мир разработки.
Одна проблема - я никак не могу написать к нему документацию, чтобы и другие разработчики могли его оценить по достоинству. Мне кажется любому программисту гораздо проще писать код, чем рассказывать, как именно он работает.
Поэтому я решил написать не просто скучную документацию, а сразу подробный обучающий курс - где мы сможем пообщаться в процессе.
Мы напишем интернет-магазин с минимальным функционалом по типу как у miniShop2, попутно пройдя все этапы создания проекта:
Вы освоите: Slim4, Eloquent, VueJS, NuxtJs, Phinx и что там еще по пути потребуется.