Uma extensão para usar o Laravel em uma configuração de vários domínios
Este pacote permite que uma única instalação do Laravel funcione com vários domínios HTTP.
Existem muitos casos em que diferentes clientes utilizam a mesma aplicação em termos de código, mas não em termos de banco de dados, armazenamento e configuração.
Este pacote oferece uma maneira muito simples de obter um arquivo env específico, um caminho de armazenamento específico e um banco de dados específico para cada cliente.
Laravel | Multidomínio |
---|---|
11.x | 11.x |
10.x | 10.x |
9.x | 5.x |
8.x | 4.x |
7.x | 3.x |
6.x | 2.x |
5.8.x | 1.4.x |
5.7.x | 1.3.x |
5.6.x | 1.2.x |
5.5.x | 1.1.x |
Lançamentos v1.1.x:
Até o momento, as versões v1.1.6+, v1.2.x, v1.3.x, v1.4.x, v2.x e v3.x são funcionalmente equivalentes. As versões foram separadas para executar testes de integração com a versão correspondente do framework Laravel.
No entanto, com o lançamento do Laravel 8, as versões v1.1.14, v1.2.8, v1.3.8 e v1.4.8 são as últimas versões, incluindo novos recursos para as versões correspondentes do Laravel 5.x (o suporte para correção de bugs ainda está ativo para essas versões) . ATUALIZAÇÃO DE 13/02/2021 : alguns recursos mais recentes para versões v1.1+ ainda estão em andamento :)
v1.0 requer Laravel 5.1, 5.2, 5.3 e 5.4 (não é mais mantido e não testado versus laravel 5.4, porém o uso do pacote é o mesmo do 1.1)
ATUALIZAÇÃO 20/02/2023 : A partir do Laravel 10.x, as versões dos pacotes seguem a mesma numeração.
Adicione gecche/laravel-multidomain como um requisito ao compositor.json:
{
"require" : {
"gecche/laravel-multidomain" : "11.*"
}
}
Atualize seus pacotes com a atualização do compositor ou instale com a instalação do compositor.
Você também pode adicionar o pacote usando composer require gecche/laravel-multidomain
e posteriormente especificar a versão desejada.
Este pacote precisa substituir a detecção do domínio HTTP em um conjunto mínimo de funções principais do Laravel logo no início do processo de inicialização para obter o arquivo de ambiente específico. Portanto, este pacote precisa de mais algumas etapas de configuração do que a maioria dos pacotes Laravel.
Etapas de instalação:
bootstrap/app.php
. //use Illuminate F oundation A pplication
use Gecche Multidomain Foundation Application
QueueServiceProvider
pelo estendido no arquivo config/app.php
da seguinte forma: ' providers ' => Illuminate Support ServiceProvider:: defaultProviders ()-> merge ([
// Package Service Providers . . .
])-> replace ([
Illuminate Queue QueueServiceProvider::class => Gecche Multidomain Queue QueueServiceProvider::class,
])-> merge ([
// Added Service Providers ( Do not remove this line ) . . .
])-> toArray (),
Observe que se você alterou o arquivo config/app.php
por outros motivos, provavelmente já existe a entrada providers
acima nesse arquivo e a única linha importante é aquela que substitui QueueServiceProvider
.
php artisan vendor:publish
(Este pacote utiliza o recurso de descoberta.)
Seguindo as etapas acima, seu aplicativo estará ciente do domínio HTTP no qual está sendo executado, tanto para solicitações HTTP quanto CLI, incluindo suporte a filas.
NOTA: no Laravel 11 a instalação é mais simples do que antes: se você utiliza uma versão anterior do Laravel, verifique na documentação os passos de instalação.
O pacote é compatível com Horizon, graças às contribuições da comunidade. Se você precisar usar este pacote junto com o Horizon você terá que seguir outras duas etapas de instalação:
Instale o Laravel Horizon normalmente
Substitua a importação do Laravel Horizon no topo do arquivo app/Providers/HorizonServiceProvider.php.
//use Laravel H orizon H orizonApplicationServiceProvider ;
use Gecche Multidomain Horizon HorizonApplicationServiceProvider ;
Este pacote adiciona três comandos para gerenciar os domínios HTTP do seu aplicativo:
domain.add
artesão O comando principal é o comando domain:add
que toma como argumento o nome do domínio HTTP a ser adicionado à aplicação. Suponhamos que temos dois domínios, site1.com
e site2.com
, compartilhando o mesmo código.
Nós simplesmente fazemos:
php artisan domain:add site1.com
e
php artisan domain:add site2.com
Estes comandos criam dois novos arquivos de ambiente, .env.site1.com
e .env.site2.com
, nos quais você pode colocar a configuração específica para cada site (ex. configuração de bancos de dados, configuração de cache e outras configurações, como normalmente encontradas em um ambiente arquivo).
O comando também adiciona uma entrada na chave domains
no arquivo config/domains.php
.
Além disso, duas novas pastas são criadas, storage/site1_com/
e storage/site2_com/
. Eles têm a mesma estrutura de pastas do armazenamento principal.
As personalizações nesta subestrutura storage
devem corresponder aos valores no arquivo config/domain.php
.
domain.remove
artesão O comando domain:remove
remove o domínio HTTP especificado do aplicativo excluindo seu arquivo de ambiente. Por exemplo:
php artisan domain:remove site2.com
Adicionar a opção force
excluirá a pasta de armazenamento do domínio.
O comando também remove a entrada apropriada da chave domains
no arquivo config/domains.php
.
domain.update_env
O comando domain:update_env
passa uma matriz de dados codificados em json para atualizar um ou todos os arquivos de ambiente. Esses valores serão adicionados no final do .env apropriado.
Atualize um único arquivo de ambiente de domínio adicionando o argumento domain
.
Quando o argumento domain
está ausente, o comando atualiza todos os arquivos de ambiente, incluindo o padrão .env
.
A lista de domínios a serem atualizados é mantida no arquivo de configuração domain.php
.
Por exemplo:
php artisan domain:update_env --domain_values='{"TOM_DRIVER":"TOMMY"}'
adicionará a linha TOM_DRIVER=TOMMY
a todos os arquivos de ambiente de domínio.
domain.list
O comando domain:list
lista os domínios atualmente instalados, com seu arquivo .env e diretório de caminho de armazenamento.
A lista é mantida na chave domains
do arquivo de configuração config/domain.php
.
Esta lista é atualizada automaticamente a cada domain:add
e domain:remove
executado.
config:cache
comando artesãoO comando config:cache artesão pode ser usado com este pacote da mesma forma que qualquer outro comando artesão.
Observe que este comando irá gerar um arquivo config.php para cada domínio sob o qual o comando foi executado. Ou seja, o comando
php artisan config:cache --domain=site2.com
irá gerar o arquivo
config-site2_com.php
Em tempo de execução, o domínio HTTP atual é mantido no contêiner laravel e pode ser acessado pelo método domain()
adicionado por este pacote.
Um método domainList()
está disponível. Ele retorna uma matriz associativa contendo as informações dos domínios instalados, semelhante ao comando domain.list
acima.
Por exemplo
[
site1.com => [
'storage_path' => <LARAVEL-STORAGE-PATH>/site1_com,
'env' => '.env.site1.com'
]
]
Para cada solicitação HTTP recebida pelo aplicativo, o arquivo de ambiente específico é carregado e a pasta de armazenamento específica é usada.
Se nenhum arquivo de ambiente e/ou pasta de armazenamento específico for encontrado, o padrão será usado.
A detecção do domínio HTTP correto é feita usando a variável $_SERVER['SERVER_NAME']
PHP.
NOTA IMPORTANTE: em alguns ambientes de execução $_SERVER['SERVER_NAME'] não é instanciado, portanto este pacote não funciona corretamente até que você personalize a detecção de domínios HTTP conforme descrito abaixo.
A partir da versão 1.1.15, a detecção de domínios HTTP pode ser customizada passando um Closure
como a entrada domain_detection_function_web
do novo argumento domainParams
do construtor de Application
. No exemplo a seguir, a detecção de domínio HTTP depende de $_SERVER['HTTP_HOST']
em vez de $_SERVER['SERVER_NAME']
.
//use Illuminate F oundation A pplication ;
use Gecche Multidomain Foundation Application ;
use Illuminate Foundation Configuration Exceptions ;
use Illuminate Foundation Configuration Middleware ;
$ environmentPath = null ;
$ domainParams = [
' domain_detection_function_web ' => function () {
return Illuminate Support Arr:: get ( $ _SERVER , ' HTTP_HOST ' );
}
];
return Application:: configure (basePath: dirname ( __DIR__ ),
environmentPath: $ environmentPath ,
domainParams: $ domainParams )
-> withRouting (
web: __DIR__ . ' /../routes/web.php ' ,
commands: __DIR__ . ' /../routes/console.php ' ,
health: ' /up ' ,
)
-> withMiddleware ( function ( Middleware $ middleware ) {
//
})
-> withExceptions ( function ( Exceptions $ exceptions ) {
//
})-> create ();
Para distinguir entre domínios, cada comando artesão aceita uma nova opção: domain
. Por exemplo:
php artisan list --domain=site1.com
O comando usará as configurações de domínio correspondentes.
Os comandos do artesão queue:work
e queue:listen
foram atualizados para aceitar uma nova opção domain
.
php artisan queue:work --domain=site1.com
Como sempre, o comando acima usará as configurações de domínio correspondentes.
Lembre-se de que se, por exemplo, você estiver usando o driver database
e tiver dois domínios compartilhando o mesmo banco de dados, deverá usar duas filas distintas se quiser gerenciar os trabalhos de cada domínio separadamente.
Por exemplo, você poderia:
QUEUE_DEFAULT=default1
para site1.com e QUEUE_DEFAULT=default2
para site2.comqueue.php
alterando a fila padrão de acordo: 'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => env('QUEUE_DEFAULT','default'),
'retry_after' => 90,
],
php artisan queue:work --domain=site1.com --queue=default1
e
php artisan queue:work --domain=site1.com --queue=default2
Obviamente, o mesmo pode ser feito para cada outro driver de fila, além do driver sync
.
storage:link
Se você usar o comando storage:link
e desejar um link simbólico distinto para cada domínio, será necessário criá-los manualmente porque até o momento tal comando sempre cria um link chamado storage
e esse nome é codificado no comando. Estender o comando storage:link
permitindo escolher o nome está fora do escopo deste pacote (e espero que seja feito diretamente em versões futuras do Laravel).
Uma forma de obter vários links de armazenamento poderia ser a seguinte. Suponhamos que temos dois domínios, nomeadamente site1.com
e site2.com
com pastas de armazenamento associadas storage/site1_com
e storage/site2_com
.
ln -s storage/site1_com/app/public public/storage-site1_com
ln -s storage/site2_com/app/public public/storage-site2_com
.env.site1.com
e .env.site2.com
adicionamos uma entrada, por exemplo, para o primeiro domínio: APP_PUBLIC_STORAGE=-site1_com
filesystems.php
, alteramos da seguinte forma: 'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage'.env('APP_PUBLIC_STORAGE'),
'visibility' => 'public',
],
Além disso, se você estiver usando o pacote em uma configuração de aplicativo de página única (SPA), poderá lidar melhor com recursos públicos distintos para cada domínio por meio de .htaccess ou soluções semelhantes, conforme apontado por Scaenicus em sua solução .htaccess.
A partir da versão 1.1.11 um segundo argumento foi adicionado ao construtor Application para escolher a pasta onde colocar os arquivos de ambiente: se você tem dezenas de domínios, não é muito agradável ter arquivos de ambiente na raiz do aplicativo Laravel pasta.
Então, se você quiser usar uma pasta diferente, basta adicioná-la no topo do arquivo bootstrap/app.php
. por exemplo, se você deseja adicionar arquivos de ambiente à subpasta envs
, basta fazer:
//use Illuminate F oundation A pplication ;
use Gecche Multidomain Foundation Application ;
use Illuminate Foundation Configuration Exceptions ;
use Illuminate Foundation Configuration Middleware ;
$ environmentPath = dirname ( __DIR__ ) . DIRECTORY_SEPARATOR . ' envs ' ;
$ domainParams = [];
return Application:: configure (basePath: dirname ( __DIR__ ),
environmentPath: $ environmentPath ,
domainParams: $ domainParams )
-> withRouting (
web: __DIR__ . ' /../routes/web.php ' ,
commands: __DIR__ . ' /../routes/console.php ' ,
health: ' /up ' ,
)
-> withMiddleware ( function ( Middleware $ middleware ) {
//
})
-> withExceptions ( function ( Exceptions $ exceptions ) {
//
})-> create ();
Se você não especificar o segundo argumento, a pasta padrão será assumida. Observe que se você especificar uma pasta, o arquivo .env
padrão também deverá ser colocado nela
Se você tentar executar uma página da web ou um comando shell em um determinado domínio, por exemplo, sub1.site1.com
e não houver nenhum arquivo de ambiente específico para esse domínio, ou seja, o arquivo .env.sub1.site1.com
não existe, o O pacote usará o primeiro arquivo de ambiente disponível dividindo o nome de domínio com pontos. Neste exemplo, o pacote procura o primeiro arquivo de ambiente entre os seguintes:
.env.site1.com
.env.com
.env
A mesma lógica também se aplica à pasta de armazenamento.
Se na sua configuração você utiliza o Scheduler do Laravel, lembre-se que também o comando schedule:run
deve ser lançado com a opção domain. Portanto, você deve lançar um agendador para cada domínio. A princípio, pode-se pensar que uma instância do Scheduler deve lidar com os comandos iniciados para qualquer domínio, mas o próprio Scheduler é executado dentro de um aplicativo Laravel, portanto, o "env" sob o qual ele é executado se aplica automaticamente a cada comando agendado e o --domain
a opção --domain
não tem efeito algum.
O mesmo se aplica a ferramentas externas como o Supervisor: se você usar o Supervisor para comandos artesanais, por exemplo, o comando queue:work
, certifique-se de preparar um comando para cada domínio que deseja manipular.
Devido ao acima exposto, existem alguns casos em que o pacote não funciona: naquelas configurações onde você não tem a possibilidade de alterar, por exemplo, a configuração do supervisor em vez das entradas crontab
para o agendador. Tal exemplo foi apontado aqui em que uma instância do Docker foi usada.
Por último, esteja ciente de que alguns comandos do Laravel chamam outros comandos do Artisan por dentro, obviamente sem a opção --domain
. A situação acima não funciona corretamente porque o subcomando funcionará com o arquivo de ambiente padrão. Um exemplo é o comando migrate
ao usar a opção --seed
.