PageBlocks 2.3.0



pbResource


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

Преимущества:
  • Максимальная гибкость: Возможность добавлять любые поля для ресурсов. Больше никаких TV полей.
  • Удобство управления: Ресурсы отображаются в специально созданной таблице, что упрощает их редактирование и исключает избыточность в стандартном дереве.
  • Фильтрация и кастомизация: Полный контроль над отображением и управлением данными с помощью кастомных таблиц и фильтров.
Пример такой таблицы с фильтрацией (все картинки кликабельны):


Relationship Field


Данное поле позволяет устанавливать связи между таблицами PageBlocks или ресурсами (pbResources). Оно обеспечивает гибкость и удобство в управлении связанными данными.

Настройка:


Доступные отношения:
  • One to One — Один к одному
  • One to Many — Один ко многим
  • Many to One — Многие к одному
  • Many to Many — Многие ко многим
Пример вывода через сниппет pbRelationship:
[[!pbRelationship? 
    &relation_type=`one_to_one`       // Тип отношения
    &primary_table=`pbTable`          // Основная таблица: pbTable или pbResources
    &primary_id=`1`                   // ID основной записи
    &tpl=`relation`                   // Чанк для вывода результатов. Доступны все поля связанного объекта
]]

Dependent Field


Dependent Field — это настройка поля, которая позволяет скрывать или отображать другие поля в зависимости от значения одного из полей формы. Это обеспечивает динамическое изменение интерфейса и упрощает ввод данных пользователями.

Пример использования:
Допустим, у вас есть таблица товаров, где есть два типа товаров: Холодильники и Телефоны. В зависимости от выбранной категории, нужно отображать разные характеристики:
  • Для холодильников: объём, количество камер, класс энергопотребления.
  • Для телефонов: диагональ экрана, объём оперативной памяти, поддержка 5G.


Imask Field


Imask Field — это текстовое поле, в котором можно использовать различные опции маскировки, обеспечивая удобный ввод данных в нужном формате. Маскировка настраивается с помощью библиотеки iMask.js



Настройки из примера:
1. Телефонный номер
{
    mask: '+{38} (000) 000-00-00'
}

2. Дата
{
    mask: Date,
    pattern: 'd{.}`m{.}`Y',
    blocks: {
        d: { mask: IMask.MaskedRange, from: 1, to: 31 },
        m: { mask: IMask.MaskedRange, from: 1, to: 12 },
        Y: { mask: IMask.MaskedRange, from: 1900, to: 2099 }
    }
}

3. Сумма
{
    mask: Number,
    thousandsSeparator: ' ',
    radix: ',',
    scale: 2
}

4. Номер кредитной карты
{
    mask: '0000 0000 0000 0000'
}

Больше пример на сайте https://imask.js.org/

Map Field


Map Field — это поле, которое позволяет интегрировать карты на вашу страницу. В данный момент доступны два типа карт: Leaflet и Yandex. В будущем планируется добавить поддержку Google Maps.

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



Для отображение карты на фронте используется сниппет pbMap:
{'!pbMap' | snippet: [
    'markers' => $map_coords,  // координаты карты
    'options' => $map_options  // опции карты
]}

Gallery Field


В этой версии улучшен интерфейс галереи, а также добавлена функция автоматической генерации превьюшек.



{"webp":{"w":120,"h":90,"q":90,"zc":"1","bg":"000000","f":"webp"}}
Эта настройка будет генерировать превьюшки размером 120x90 пикселей и сохранять их в папке webp в формате webp.

Другие поля


Помимо прочего, в компонент были добавлены еще новые типы полей, а также улучшено старое поле:
  • TableMultiCombo Field
  • MultiCombo Field
  • Currency Field
  • Heading Field
  • Tag Field
  • KeyValue Field (улучшенно)

Routing


В компоненте PageBlocks появилась поддержка роутинга, благодаря чему теперь можно создавать маршруты, обрабатывать запросы и возвращать данные в различных форматах. Это делает разработку API-интерфейсов для MODX проще и интуитивно понятнее.

При установке компонента в папке core создается директория App, которая предназначена для настройки и управления различными аспектами работы компонента:
  • Маршруты: App/routes
  • Контроллеры: App/Http/Controllers
  • Мидлвары: App/Http/Middleware
  • Шаблоны для Fenom: App/elements
  • Модификаторы для Fenom: App/Helpers/modifiers.php

Примеры маршрутов:


Использование функции, возвращающей текст:
Route::get('/hello', function () { 
    return 'Hello World';
});

Использование контроллера:
Route::get('/resource', [ResourceController::class, 'index']);
Route::get('/resource/{id}', 'ResourceController@show');

Пример контроллера


namespace PageBlocks\App\Http\Controllers;

class ResourceController extends Controller
{
    public $classKey = \modResource::class;

    public function index(string $key, array $request)
    {
        $resources = $this->modx->getIterator($this->classKey, [
            'context_key' => $key,
            'published' => 1,
        ]);
        return $resources;
    }

    public function show($key, $id, array $request)
    {
        return $this->modx->getObject($this->classKey, $id);
    }
}
Объекты будут автоматически преобразованы в JSON.

Response


Контроллеры могут возвращать не только текст или массив, но и объекты класса Response. Это позволяет гибко управлять выводом данных.

Пример:
public function view($id, array $request)
{
    $resource = $this->modx->getObject($this->classKey, $id);
    $data = ['resource' => $resource];

    return response()->view('templates/index', $data);
}

Методы класса Response:

1. Выводит текстовый ответ.

text($text, int $status = 200, array $headers = [])

  • $text — текст ответа.
  • $status — HTTP-статус (по умолчанию 200).
  • $headers — дополнительные заголовки.
Пример:
return response()->text('Hello World', 200, ['Content-Type' => 'text/plain']);
// или тоже самое:
return response()->text('Hello World');

2. Возвращает данные в формате JSON.

json(array $data, int $status = 200, array $headers = [])

  • $data — массив данных для преобразования.
  • $status — HTTP-статус (по умолчанию 200).
  • $headers — дополнительные заголовки.
Пример:
return response()->json(['message' => 'Success']);

3. Рендерит шаблон и возвращает HTML.

view(string $template, array $data = [])

  • $template — путь к шаблону, который должен находиться в папке App/elements.
  • $data — массив данных, передаваемых в шаблон.
Шаблон обрабатывается через Fenom, встроенный в компонент.

Пример:
return response()->view('templates/resource', ['title' => 'My Resource']);

4. Выполняет перенаправление на указанный URL.

redirect(string $url, int $status = 302, array $headers = [])

  • $url — адрес для редиректа.
  • $status — HTTP-статус (по умолчанию 302).
  • $headers — дополнительные заголовки.
Пример:
return response()->redirect('/new-url', 301);

5. Возвращает файл для скачивания.

download(string $file, string $name = null, array $headers = [])

  • $file — путь к файлу, от корня сайта.
  • $name — имя файла для загрузки (необязательно).
  • $headers — дополнительные заголовки.
Пример:
return response()->download('path/to/file.zip', 'myfile.zip');

Без контроллера:


Для выполнения редиректов не обязательно вызывать контроллер, это можно сделать прямо в маршруте:
Route::redirect('/here', '/there');

Вывод шаблона
Route::get('/', function () {
    return view('templates/welcome');
});
// или еще короче
Route::view('/', 'templates/welcome');

Редирект на именованный роут
Route::get('/', function () {
    return view('templates/welcome');
})->name('welcome');

// теперь мы можем сделать редирект по названию маршрута
Route::get('/wel_come', function () {
    return redirect()->route('welcome');
});


Примеры роутов:


С префиксом, группой и мидлваром.
use Boshnik\PageBlocks\Routing\Route;
use PageBlocks\App\Http\Controllers\ConfigController;
use PageBlocks\App\Http\Controllers\ContextController;
use PageBlocks\App\Http\Controllers\ResourceController;

Route::prefix('api')->middleware(['Authenticate'])->group(function () {

    Route::get('/context/', [ContextController::class, 'index']);
    Route::get('/config/', [ConfigController::class, 'index']);

    Route::prefix('{key}')->group(function () {
        Route::get('/menu', [ResourceController::class, 'menu']);

        Route::get('/resource', [ResourceController::class, 'index']);
        Route::get('/resource/{id}', [ResourceController::class, 'show']);
    });
});

Данный роутинг API создает следующую структуру ссылок:
  1. Контроллер ContextController:
    • /api/context/
  2. Контроллер ConfigController:
    • /api/config/
  3. Контроллер ResourceController:
    • /api/{key}/menu
    • /api/{key}/resource
    • /api/{key}/resource/{id}
Каждый роут обрабатывается мидлваром Authenticate, и если пользователь не авторизован, то возвращаем ему 401 ошибку с текстом «Unauthorized».

Получаем все роуты
Route::get('/route/list', function () {
    return Route::getRoutes();
});

Интеграция, вдохновленная Laravel


Роутинг в PageBlocks максимально приближен к синтаксису и подходам Laravel. Это позволяет легко адаптировать примеры из документации Laravel для использования в PageBlocks.

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

Ключевые преимущества PageBlocks:


  • Отказ от избыточности TV: Забудьте о множестве TV-полей, засоряющих интерфейс и усложняющих структуру. PageBlocks позволяет создавать собственные поля с любыми необходимыми настройками.
  • Гибкость и настраиваемость: Вы сами определяете структуру данных, создавая таблицы с необходимыми полями и устанавливая связи между ними.
  • Улучшенный интерфейс: Управление данными становится удобнее благодаря табличному представлению, фильтрации и динамическому отображению полей.
  • Расширенные возможности ввода: Imask Field, Dependent Field и другие типы полей делают ввод данных более удобным и интуитивным для контент-менеджеров.
  • Интеграция с внешними сервисами: Map Field позволяет легко интегрировать карты, а галерея с генерацией превьюшек упрощает управление изображениями.
  • Разработка API: Благодаря системе роутинга, создание RESTful API становится простым и интуитивно понятным процессом. Синтаксис, вдохновленный Laravel, позволяет с легкостью применять готовые решения и ускорить разработку.
  • Постоянное развитие: Компонент активно развивается и пополняется новыми функциями и возможностями.
Итого:

PageBlocks — это не просто дополнение, это полноценная платформа для управления данными в MODX, которая выводит ваши возможности на новый уровень. Благодаря ей вы сможете создавать более сложные и гибкие проекты, с легкостью настраивая структуру контента и интерфейс управления.

Поддержка:


  • MODX: 2 / 3
  • PHP: ^7.4
  • Поля: 37 разнообразных полей
Aleksandr Huz
27 января 2025, 09:34
modx.pro
1
606
+20
Поблагодарить автора Отправить деньги

Комментарии: 8

Николай Савин
27 января 2025, 11:11
+4
Это безумно круто. Я в восторге
    Баха Волков
    27 января 2025, 13:20
    +4
    Отличное обновление!
      Дмитрий
      27 января 2025, 14:11
      +4
      Выглядит очень-очень круто!
        Rus
        Rus
        27 января 2025, 17:50
        +3
        Уже второй месяц работаю с PageBlocks. До этого городил что-то похожее на MIGX.

        Автор всегда на связи и при появлении каких-либо сложностей, связанных с компонентом, реагирует быстро. PageBlocks — это мощь!
          Андрей Шевяков
          27 января 2025, 20:09
          +3
          Уже ни один проект собран на PageBlocks, доп. шикарный!
          Радует, что вернулась поддержка PHP 7.4
            Aleksandr Huz
            28 января 2025, 01:22
            +3
            Version 2.3.1

            Added
            • support MySQL 5.7
            • description for ready blocks
            • support for custom parameters for snippets
            @Баха Волков @Rus
              Олег Захаров
              01 февраля 2025, 00:41
              0
              Жаба душит. Но посмотрел состав и подумал что оно стоит того.
              Как реализовано управление мультиязычности немного не понял.
              Я использую Localizator и немного дорабатываю под себя. Не будет конфликтовать? Как реализовано управление переводами элементов и доп. полей (все таки они могут использоваться, и надо бы их Вашим компонентом тоже поддерживать?), а также как реализовано управление лексиконами и словарями?
                Aleksandr Huz
                01 февраля 2025, 01:10
                +1
                Про мультиязычность напишу отдельную статью. Вкратце: есть комбо-поле, которое переключает контекст для блоков, которые можно переводить вручную или с помощью сторонних сервисов (DeepL, ChatGPT). Также есть отдельная вкладка для перевода текущего ресурса — по принципу Локализатора. Конфликтов не должно быть. Дополнительные поля я не использую с этим компонентом — ни разу не пригодились. Вся информация находится в блоках, поэтому отдельной вкладки для лексиконов, как в Локализаторе, тоже нет.
                Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                8