Разработка каналов доставки RePost
Провайдер RePost — канал доставки: Telegram, VK, webhook, своя БД, внешний API и т.п.
Контракт: ProviderInterface → рекомендуется extends AbstractProvider → send(…): SendResult.
flowchart TB
Dispatch[DispatchService] --> Registry[ProviderRegistry]
Registry --> P[ProviderInterface]
P --> Abstract[AbstractProvider]
Abstract --> TG[TelegramProvider]
Abstract --> Custom[Webhook / DB / API / ...]
P --> DTO["PostContext + RenderedMessage → SendResult"]Структура каталога
devcraft/src/modules/RePost/Provider/
├── ProviderInterface.php
├── AbstractProvider.php # ok/fail + mediaByteLimits + allowedMediaExtensions + filterMediaByLimits + templateTags()
├── TemplateTagsInterface.php
├── DefaultTemplateTags.php
├── ProviderRegistry.php
└── MyChannel/
├── init.php
├── settings.schema.php
└── MyChannelProvider.phpinit.php
return [
'name' => 'mychannel',
'title' => 'My Channel',
'version' => '200.1.0',
'class' => \DevCraft\Modules\RePost\Provider\MyChannel\MyChannelProvider::class,
];ProviderRegistry сканирует подкаталоги с init.php и регистрирует по ключу name.
Обязательно: теги шаблона (TemplateTagsInterface)
Каждый канал должен вернуть реализацию из templateTags():
implements TemplateTagsInterfaceилиextends DefaultTemplateTags- свои HTML-теги канала — в
allowedHtmlTags()/sanitizeHtml() - UI-чипы редактора —
hints(); post-pass —applyAfterParse(); плейсхолдеры —extraPlaceholders()
По умолчанию AbstractProvider::templateTags() → DefaultTemplateTags.
Telegram: TelegramTemplateTags (кнопки, [repost_media_*], allowlist Bot API).
Provider/
TemplateTagsInterface.php
DefaultTemplateTags.php
Telegram/TelegramTemplateTags.phpContentRenderer вызывает tags выбранного подключения после ParseTemplateTags::apply.
Обязательно: лимиты медиа
Каждый extends AbstractProvider должен:
- Реализовать
mediaByteLimits(): array— ключиphoto/video/audio/document→ байты. Нет ключа или0= без лимита для типа. - В
send()до аплоада вызватьfilterMediaByLimits($message)и работать уже с отфильтрованнымRenderedMessage.
Локальные файлы больше лимита отбрасываются; публичный URL без локального файла остаётся (размер неизвестен). В skipped — список отброшенных (path, kind, bytes, limit).
Webhook / БД без лимитов:
protected function mediaByteLimits(): array {
return []; // фильтр всё равно вызывается — no-op по размеру
}Telegram: см. Provider/Telegram/MediaLimits.php (photo 10 MiB, video/audio/document 50 MiB).
Обязательно: расширения медиа (allowedMediaExtensions)
/** @return array{photo: list<string>, video: list<string>, audio: list<string>, document: list<string>} */
public function allowedMediaExtensions(): array;- Default в
AbstractProvider— пустые списки (не фильтровать по расширению). - Telegram: photo
jpg,jpeg,png,gif,webp; videomp4; audiomp3,m4a; document — без жёсткого списка. - Несовпадение заявленного типа с allowlist → переклассификация / отправка как document.
- Внешний
url=перед аплоадом скачивается на сервер (downloadRemoteMedia); private/localhost — skip.
Минимальный класс
final class MyChannelProvider extends AbstractProvider {
public static function code(): string {
return 'mychannel';
}
public static function meta(): array {
return [
'name' => 'mychannel',
'title' => 'My Channel',
'version' => '200.1.0',
];
}
protected function mediaByteLimits(): array {
return [];
}
public function settingsSchema(): FormSchema {
return require DLEPlugins::Check(__DIR__ . '/settings.schema.php');
}
public function send(
PostContext $context,
RenderedMessage $message,
array $connectionConfig,
?array $proxy = null,
): SendResult {
$filtered = $this->filterMediaByLimits($message);
$message = $filtered['message'];
$skipped = $filtered['skipped'];
$url = trim((string) ($connectionConfig['webhook_url'] ?? ''));
if($url === '') {
return $this->fail(__('Не задан URL'));
}
// … доставка по $message …
return $this->ok(__('Отправлено'), [
'status' => 200,
'skipped_oversized' => $skipped,
]);
}
}connectionConfig— JSON изsettingsSchema().RenderedMessageуже отфильтрован поtg_send_typeв ContentRenderer; лимиты размера — зона провайдера.- Ошибки —
$this->fail()→ Admin logs (LogGenerator::for('RePost')).
Примерный settings.schema.php
FormSchemaBuilder как в Provider/Telegram/settings.schema.php.
Чеклист
- Каталог
Provider/{Code}/+init.php+ класс + schema. extends AbstractProvider+mediaByteLimits()+ при необходимостиallowedMediaExtensions().templateTags()—DefaultTemplateTagsили свой класс (TemplateTagsInterface).- В
send()вызватьfilterMediaByLimits()до аплоада. - Подключение в админке → шаблон → add/edit или cron.
Платные / внешние каналы
Каналы вроде VK поставляются отдельным ZIP (свой install.xml + дерево upload/…/Provider/{Code}/), а не патчами ядра RePost.
needplugin→ RePost- Composer-зависимости канала — notice + при необходимости патч
composer_requiredвmanifest.phpRePost - Vendor в ZIP не кладётся
Пример: providers/vk.md (RePost Provider: VK).