Anatomia de um módulo e module.json
O layout de pasta, todo campo do manifesto, e os métodos de ciclo de vida que o kernel chama.
Um módulo é um diretório autocontido, carregável em tempo de execução e instalável a partir de um zip. Os módulos de fábrica usam exatamente esse contrato.
Layout de pasta#
modules/directory/
module.json manifesto (obrigatório)
src/
DirectoryServiceProvider.php
Models/
Http/Controllers/
Http/Requests/
Support/
database/
migrations/ as tabelas do módulo
seeders/
resources/
views/ Blade, sobrescrevível por um tema
lang/ as traduções do módulo
assets/ css e js, JÁ COMPILADOS
routes/
web.php
admin.php
config/directory.php
O manifesto#
{
"name": "Directory",
"slug": "directory",
"version": "1.2.0",
"description": "A configurable catalogue.",
"author": { "name": "You", "url": "https://example.com" },
"requires": {
"bondry": ">=1.0 <2.0",
"php": ">=8.2",
"extensions": ["gd"],
"modules": { "payments": ">=1.0" }
},
"provider": "Modules\\Directory\\DirectoryServiceProvider",
"provides": {
"permissions": ["directory.view", "directory.manage"],
"hooks": ["profile.tabs", "admin.menu", "search.sources"]
},
"settings": "admin.directory.settings",
"assets": { "css": ["assets/directory.css"], "js": ["assets/directory.js"] },
"parent": null,
"tested_up_to": "1.4.0",
"official": false,
"licensing": { "product_slug": "your-directory" }
}
| Campo | Significado |
|---|---|
slug |
A identidade. [a-z0-9-], único, e nunca muda entre versões. |
version |
Semver. É o que dispara onUpdate. |
requires |
Faixas semver. O kernel recusa a instalação quando não são atendidas. |
provider |
A classe raiz. Ela precisa existir e estender o provider base. |
provides.permissions |
Registradas na matriz de grupo na instalação. |
settings |
Um nome de rota. A lista de módulos aponta para ela quando o módulo está ativo. |
parent |
O slug do módulo que este estende. Ausente significa que estende o core. |
tested_up_to |
A versão mais nova do core contra a qual você testou. |
official |
Só é aceito para pacotes assinados por nós. |
licensing.product_slug |
Presente só num módulo pago. Veja License API. |
O service provider#
Seu provider estende Bondry\Kernel\Modules\ModuleServiceProvider e
implementa o ciclo de vida:
interface ModuleContract
{
// Toda requisição, só enquanto o módulo está ativo:
public function register(): void; // bindings do container
public function boot(): void; // rotas, views, migrações, traduções, hooks
// Chamado pelo instalador em tempo de execução, não a cada requisição:
public function onInstall(): void;
public function onUninstall(bool $purge): void;
public function onEnable(): void;
public function onDisable(): void;
public function onUpdate(string $from, string $to): void;
}
boot() é onde você chama loadRoutesFrom, loadViewsFrom com seu
namespace, loadMigrationsFrom, loadTranslationsFrom e registra seus hooks.
register() roda antes de qualquer coisa ser resolvida: só bindings, sem
banco de dados.
Aviso
boot()roda em toda requisição. Qualquer coisa custosa ali é um custo que seus compradores pagam a cada visualização de página, em hospedagem compartilhada.
Views e o tema#
Registre suas views com um namespace:
$this->loadViewsFrom(__DIR__.'/../resources/views', 'directory');
Renderizar directory::item.show então resolve primeiro pela cadeia de tema,
então um comprador pode sobrescrever qualquer tela do seu módulo a partir do
tema dele sem editar seus arquivos. Veja Temas.
Fluxo de instalação#
O que o painel faz com o seu zip, em ordem:
- abre-o num diretório temporário isolado;
- lê
module.jsone valida o schema; - verifica
requirese qualquer conflito de slug ou versão; - verifica a assinatura quando
officialestá definido; - move para
modules/<slug>/e rodaonInstall(), ouonUpdate()quando já havia uma versão presente; - publica os assets em
public/modules/<slug>/; - registra na tabela de módulos;
- limpa os caches de rota, view e config.