Desenvolvimento de Pacotes
Introdução
Os pacotes são o principal meio de adição de funcionalidade à Laravel. Esses pacotes podem ser qualquer coisa, desde uma excelente forma de trabalhar com datas como Carbon até um pacote que permite associar arquivos a modelos Eloquent como o Spatie's Laravel Media Library.
Existem vários tipos de pacotes. Há pacotes autônomos, que funcionam com qualquer estrutura PHP. O Carbon e o Pest são exemplos de pacotes autônomos. Qualquer um destes pacotes pode ser utilizado com o Laravel adicionando-o no arquivo composer.json
.
Por outro lado, outros pacotes são destinados especificamente ao uso com Laravel. Esses pacotes podem incluir roteamento, controladores, visualizações e configurações voltadas especificamente para melhorar a aplicação do Laravel. Este guia aborda principalmente o desenvolvimento de pacotes que são específicos para o Laravel.
Uma nota sobre facades
Quando você está escrevendo um aplicativo do Laravel geralmente não importa se você usa contratos ou facades, pois ambos fornecem níveis essencialmente iguais de capacidade de teste. No entanto, ao escrever pacotes, seu pacote normalmente não terá acesso a todas as ajudas de testes do Laravel. Se você gostaria de poder escrever seus testes em um pacote como se o pacote estivesse instalada dentro de um aplicativo típico do Laravel, você pode usar o pacote Orchestral Testbench.
Descoberta de pacotes
O arquivo bootstrap/providers.php
de uma aplicação Laravel contém a lista dos provedores de serviços que devem ser carregados pelo Laravel. No entanto, em vez de exigir que os usuários adicionem manualmente seu provedor de serviço na lista, você pode definir o provedor na seção extra
do arquivo composer.json
do pacote para que ele seja carregado automaticamente pelo Laravel. Além dos provedores, é possível listar também quaisquer facades que você gostaria de registrar:
"extra": {
"laravel": {
"providers": [
"Barryvdh\\Debugbar\\ServiceProvider"
],
"aliases": {
"Debugbar": "Barryvdh\\Debugbar\\Facade"
}
}
},
Depois que seu pacote estiver configurado para descoberta, o Laravel irá registrar automaticamente seus provedores de serviço e facades quando instalados, criando uma experiência conveniente para os usuários do seu pacote.
Opção de não deteção de pacotes
Se você é um consumidor de pacote e deseja desativar o descobrimento do pacote para ele, você pode listar seu nome na seção extra
do arquivo composer.json
da sua aplicação:
"extra": {
"laravel": {
"dont-discover": [
"barryvdh/laravel-debugbar"
]
}
},
Você pode desativar a descoberta de pacotes para todos os pacotes usando o caractere *
dentro da diretiva dont-discover
do seu aplicativo:
"extra": {
"laravel": {
"dont-discover": [
"*"
]
}
},
Provedores de Serviços
Provedores de serviços são o ponto de conexão entre seu pacote e o Laravel. Um fornecedor de serviço é responsável por vincular itens ao container de serviços do Laravel e informar ao mesmo onde carregar recursos do pacote, como as visualizações, a configuração e os arquivos de idiomas.
Um provedor de serviços expande a classe Illuminate\Support\ServiceProvider
e contém dois métodos: register
e boot
. A classe base ServiceProvider
está localizada no pacote Composer illuminate/support
, que você deve adicionar como dependência ao seu próprio pacote. Para saber mais sobre a estrutura e o objetivo dos provedores de serviços, confira a documentação.
Recursos
Configuração
Normalmente, você precisa publicar o arquivo de configuração do seu pacote para a pasta config
da aplicação. Isso permitirá que os usuários do seu pacote substituam facilmente as opções de configuração padrão. Para permitir que seus arquivos de configuração sejam publicados, chame o método publishes
do método boot
do provedor de serviço:
/**
* Inicialize qualquer serviço de pacote.
*/
public function boot(): void
{
$this->publishes([
__DIR__.'/../config/courier.php' => config_path('courier.php'),
]);
}
Agora, quando os usuários do seu pacote executarem o comando vendor:publish
do Laravel, seu arquivo será copiado para a localização de publicação especificada. Depois que sua configuração tiver sido publicada, seus valores podem ser acessados como se fossem um arquivo de configuração qualquer:
$value = config('courier.option');
ATENÇÃO
Você não deve definir closures em seus arquivos de configuração. Eles não podem ser serializados corretamente quando os usuários executam o comando config:cache
no Artisan.
Configuração padrão do pacote
Também é possível fundir seu próprio arquivo de configuração do pacote com a cópia publicada da aplicação, permitindo que seus usuários definam apenas as opções que desejam substituir na cópia publicada do arquivo de configuração. Para fundir os valores do arquivo de configuração, utilize o método mergeConfigFrom
dentro do método register
do provedor de serviços.
O método mergeConfigFrom
aceita o caminho para o arquivo de configuração do seu pacote como seu primeiro argumento e o nome da cópia do aplicativo do arquivo de configuração como seu segundo argumento:
/**
* Registre quaisquer serviços de aplic_assets_.
*/
public function register(): void
{
$this->mergeConfigFrom(
__DIR__.'/../config/courier.php', 'courier'
);
}
ATENÇÃO
Esse método somente mescla o primeiro nível da matriz de configurações. Se os usuários definirem parcialmente uma matriz de configuração multidimensional, as opções ausentes não serão mescladas.
Rotas
Se o seu pacote contiver rotas, você poderá carregá-las usando o método loadRoutesFrom
. Este método automaticamente determinará se as rotas da aplicação estão em cache e não carregará o arquivo de rotas se já estiverem disponíveis no cache:
/**
* Inicialize qualquer serviço de pacote.
*/
public function boot(): void
{
$this->loadRoutesFrom(__DIR__.'/../routes/web.php');
}
Migrações
Se o seu pacote incluir migrações de base de dados, poderá utilizar a método publishesMigrations
para informar ao Laravel que determinado diretório ou arquivo contém migrações. Quando o Laravel publica as migrações, atualiza automaticamente a marcação da data e hora no nome dos arquivos:
/**
* Inicialize qualquer serviço de pacote.
*/
public function boot(): void
{
$this->publishesMigrations([
__DIR__.'/../database/migrations' => database_path('migrations'),
]);
}
Arquivos de idiomas
Se o seu pacote conter arquivos de idiomas, você pode usar o método loadTranslationsFrom
para informar ao Laravel como carregá-los. Por exemplo, se o nome do seu pacote for courier
, você deve adicionar o seguinte ao método boot
de seu provedor de serviços:
/**
* Inicialize qualquer serviço de pacote.
*/
public function boot(): void
{
$this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
}
As linhas de tradução do pacote são referenciadas usando a convenção de sintaxe package::file.line
. Então, você pode carregar a linha welcome
do pacote courier
do arquivo messages
, da seguinte forma:
echo trans('courier::messages.welcome');
É possível registrar arquivos de tradução em formato JSON para o seu pacote através do método loadJsonTranslationsFrom
. Este método aceita como parâmetro o caminho ao diretório que contém os arquivos de tradução JSON do seu pacote:
/**
* Inicialize qualquer serviço de pacote.
*/
public function boot(): void
{
$this->loadJsonTranslationsFrom(__DIR__.'/../lang');
}
Publicando arquivos de idioma
Se pretender publicar os arquivos de idiomas do seu pacote no diretório lang/vendor
da aplicação, você pode utilizar o método publishes
do provedor de serviços. O método publishes
aceita um array de caminhos de pacotes e locais de publicação desejados. Por exemplo, se pretender publicar os arquivos de idiomas para o pacote courier
, você pode executar o seguinte:
/**
* Inicialize qualquer serviço de pacote.
*/
public function boot(): void
{
$this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
$this->publishes([
__DIR__.'/../lang' => $this->app->langPath('vendor/courier'),
]);
}
Agora, quando os usuários do seu pacote executarem o comando Artisan vendor:publish
do Laravel, os arquivos de idioma do seu pacote serão publicados no local de publicação especificado.
Visualizações
Para registrar as views do seu pacote com Laravel, você precisa informar a localização das views para o Laravel. Isso pode ser feito usando o método loadViewsFrom
do provedor de serviços. O método loadViewsFrom
aceita dois argumentos: o caminho dos modelos de visualização e o nome do seu pacote. Por exemplo, se o nome do seu pacote for courier
, você adicionaria o seguinte ao método boot
do provedor de serviços:
/**
* Inicialize qualquer serviço de pacote.
*/
public function boot(): void
{
$this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
}
As views de um pacote são referenciados usando a convenção de sintaxe package::view
. Então, assim que seu caminho da view é registrado em um provedor de serviços, você poderá carregar o visualizador dashboard
do pacote courier
desta forma:
Route::get('/dashboard', function () {
return view('courier::dashboard');
});
Substituindo views de pacotes
Quando você usa o método loadViewsFrom
, o Laravel registra duas localizações para suas views: a pasta de recursos/views/vendor
da aplicação e a pasta que especificou. Então, como exemplo, o Laravel verifica se uma versão personalizada da view foi colocada na pasta resources/views/vendor/courier
pelo desenvolvedor. Em seguida, se a view não tiver sido personalizada, o Laravel procurará pela pasta de views do pacote especificado em sua chamada para loadViewsFrom
. Isso torna fácil para os usuários de pacotes customizarem/substituírem as views do seu pacote.
Visualização de publicações
Se você pretender disponibilizar as suas views para publicação no diretório de recursos da aplicação 'resources/views/vendor'
, poderá utilizar o método 'publishes'
do provedor. O método publishes
aceita uma matriz com os caminhos das views do pacote e os locais de publicação pretendidos:
/**
* Inicialize os serviços do pacote.
*/
public function boot(): void
{
$this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
$this->publishes([
__DIR__.'/../resources/views' => resource_path('views/vendor/courier'),
]);
}
Agora, quando os usuários de seu pacote executarem o comando do Laravel vendor:publish
, as views do pacote serão copiadas para a localização de publicação especificada.
Visualizar componentes
Se você estiver construindo um pacote que utiliza componentes Blade ou colocando componentes em diretórios não convencionais, precisará registrar manualmente sua classe de componente e seu alias do HTML tag para que o Laravel saiba onde encontrar o componente. Tipicamente, registre seus componentes no método boot
do provedor de serviço do seu pacote:
use Illuminate\Support\Facades\Blade;
use VendorPackage\View\Components\AlertComponent;
/**
* Inicialize os serviços do seu pacote.
*/
public function boot(): void
{
Blade::component('package-alert', AlertComponent::class);
}
Depois que o componente tiver sido registrado, ele poderá ser utilizado através de seu alias de tag:
<x-package-alert/>
Autoloading de Componentes do pacote
Alternativamente, você pode usar o método componentNamespace
para carregar componentes por convenção. Por exemplo, um pacote com os nomes de classe Nightshade
e ColorPicker
, que residem no namespace Nightshade\Views\Components
, seriam:
use Illuminate\Support\Facades\Blade;
/**
* Inicialize os serviços do seu pacote.
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}
Isso permitirá o uso de componentes do pacote pelo namespace do fornecedor usando a sintaxe package-name::
:
<x-nightshade::calendar />
<x-nightshade::color-picker />
O Blade detectará automaticamente a classe que está vinculada a este componente colocando o nome do componente em pascal-case. Subdiretórios também são suportados usando a notação "dot".
Componentes anônimos
Se o seu pacote conter componentes anônimos, estes devem ser colocados num diretório components
, no diretório de views do seu pacote (como especificado pelo método loadViewsFrom
). Você pode assim renderizá-los utilizando um prefixo com o nome do componente:
<x-courier::alert />
About do comando Artisan
O comando about
embutido do Laravel fornece uma síntese do ambiente e da configuração da aplicação. Os pacotes podem enviar informações adicionais para a saída deste comando através da classe AboutCommand
. Normalmente, essas informações podem ser adicionadas na seu provedor de serviço no pacote:
use Illuminate\Foundation\Console\AboutCommand;
/**
* Inicialize qualquer serviço de aplicativo.
*/
public function boot(): void
{
AboutCommand::add('My Package', fn () => ['Version' => '1.0.0']);
}
Comandos
Para registrar comandos do pacote Artisan no Laravel, você pode usar o método commands
. Este método espera um array de nomes das classes dos commandos. Depois que os comandos forem registrados, você poderá executá-los usando a CLI do Artisan:
use Courier\Console\Commands\InstallCommand;
use Courier\Console\Commands\NetworkCommand;
/**
* Inicialize qualquer serviço de pacote.
*/
public function boot(): void
{
if ($this->app->runningInConsole()) {
$this->commands([
InstallCommand::class,
NetworkCommand::class,
]);
}
}
Assets públicos
Seu pacote pode conter recursos como JavaScript, CSS e imagens. Para publicar esses recursos no diretório public
da aplicação, use o método publishes
do provedor de serviço. Nesse exemplo, também será adicionado um marcador de grupo de recurso public
, que pode ser usado para facilitar a publicação de grupos relacionados de recursos:
/**
* Inicialize qualquer serviço de pacote.
*/
public function boot(): void
{
$this->publishes([
__DIR__.'/../public' => public_path('vendor/courier'),
], 'public');
}
Agora, quando os usuários de um pacote executarem o comando vendor:publish
, seus assets serão copiados para o local especificado. Como é necessário que os usuários substituam todos os assets sempre que o pacote for atualizado, você pode usar a opção --force
:
php artisan vendor:publish --tag=public --force
Publicando grupos de arquivos
Talvez você queira publicar grupos de assets e recursos do pacote separadamente. Por exemplo, talvez você queira permitir aos seus usuários publicarem os arquivos de configuração do seu pacote sem ser forçado a publicar os assets do pacote. Você pode fazer isso "marcando" (taggning) quando chamar o método publishes
a partir de um provedor de serviços do pacote. Nesse exemplo, vamos usar tags para definir dois grupos de publicação para o pacote courier
(courier-config
e courier-migrations
) no método boot
do provedor de serviços do pacote:
/**
* Inicialize qualquer serviço de pacote.
*/
public function boot(): void
{
$this->publishes([
__DIR__.'/../config/package.php' => config_path('package.php')
], 'courier-config');
$this->publishesMigrations([
__DIR__.'/../database/migrations/' => database_path('migrations')
], 'courier-migrations');
}
Agora os usuários podem publicar esses grupos separadamente, referenciando a tag deles ao executarem o comando vendor:publish
:
php artisan vendor:publish --tag=courier-config