1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-02-05 08:24:05 +00:00

Merge branch 'db-users' into dbusers

This commit is contained in:
Samuel Štancl 2020-04-28 21:07:47 +02:00 committed by GitHub
commit d0423cfd29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 337 additions and 119 deletions

12
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: stancl
patreon: samuelstancl
open_collective: # Replace with a single Open Collective username
ko_fi: samuelstancl
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['https://www.paypal.me/samuelstancl', 'https://gumroad.com/l/tenancy']

31
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,31 @@
name: CI
env:
COMPOSE_INTERACTIVE_NO_CLI: 1
on:
push:
branches: [ 2.x ]
pull_request:
branches: [ 2.x ]
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
laravel: ["^6.0", "^7.0"]
steps:
- uses: actions/checkout@v2
- name: Start docker containers
run: docker-compose up -d
- name: Install dependencies
run: docker-compose exec -T test composer require --no-interaction "laravel/framework:${{ matrix.laravel }}"
- name: Run tests
run: ./fulltest
- name: Send code coverage to codecov
env:
CODECOV_TOKEN: 24382d15-84e7-4a55-bea4-c4df96a24a9b
run: bash <(curl -s https://codecov.io/bash)

View file

@ -1,26 +0,0 @@
env:
- LARAVEL_VERSION="^7.0"
- LARAVEL_VERSION="^6.0"
# language: php
# php:
# - '7.4'
services:
- docker
before_install:
- docker-compose up -d
install:
- travis_retry docker-compose exec test composer require --no-interaction "laravel/framework:$LARAVEL_VERSION"
- travis_retry docker-compose exec test composer install --no-interaction
before_script:
- export DB_USERNAME=root DB_PASSWORD="" DB_DATABASE=tenancy CODECOV_TOKEN="24382d15-84e7-4a55-bea4-c4df96a24a9b"
- cat vendor/laravel/framework/src/Illuminate/Foundation/Application.php| grep 'const VERSION'
script: ./fulltest
after_success:
- bash <(curl -s https://codecov.io/bash)

View file

@ -4,9 +4,15 @@ Any donations will be greatly appreciated and help ensure that the package is de
If you're a company and this package is helping you make money, please consider donating. If you're a company and this package is helping you make money, please consider donating.
**If you'd like to donate in your local currency, see the Bank transfer section.**
### Patreon
If you would like to support me on a monthly basis, you can use Patreon: https://patreon.com/samuelstancl
### PayPal ### PayPal
PayPal is the preferable donation method as it comes with the lowest fees. PayPal is the preferable donation method for one-time donations as it comes with the lowest fees.
You can donate here: [https://paypal.me/samuelstancl](https://paypal.me/samuelstancl) You can donate here: [https://paypal.me/samuelstancl](https://paypal.me/samuelstancl)
@ -16,11 +22,17 @@ If you can't use PayPal, you may use my Gumroad link. This comes with higher fee
You can donate here: [https://gumroad.com/l/tenancy](https://gumroad.com/l/tenancy) You can donate here: [https://gumroad.com/l/tenancy](https://gumroad.com/l/tenancy)
### Bank transfer
If you'd like to donate money from your bank account, you can can do that too. I use [TransferWise](https://transferwise.com/invite/u/samuels1719) (affiliate link 🙂), so I can accept bank transfers in virtually any currency.
Contact me on [samuel.stancl@gmail.com](mailto:samuel.stancl@gmail.com?subject=Donation) and I'll give you bank details for your local currency.
### Legal ### Legal
If you're a business making a donation, you may want an invoice. If you're a business making a donation, you may want an invoice.
Contact me on [samuel.stancl@gmail.com](mailto:samuel.stancl@gmail.com) and let me know what you need to have on the invoice and I will make it happen. Contact me on [samuel.stancl@gmail.com](mailto:samuel.stancl@gmail.com?subject=Donation%20with%20invoice) and let me know what you need to have on the invoice and I will make it happen.
### Thank you! ### Thank you!

View file

@ -1,16 +1,16 @@
<p align="center"> <p align="center">
<a href="https://tenancy.samuelstancl.me"><img width="400" height="335" src="/art/logo.png" alt="Tenancy logo" /></a> <a href="https://tenancyforlaravel.com"><img width="800" src="/art/logo.png" alt="Tenancy for Laravel logo" /></a>
</p> </p>
<p align="center"> <p align="center">
<a href="https://laravel.com"><img alt="Laravel 6.x" src="https://img.shields.io/badge/laravel-6.x-red.svg"></a> <a href="https://laravel.com"><img alt="Laravel 6.x" src="https://img.shields.io/badge/laravel-6.x-red.svg"></a>
<a href="https://packagist.org/packages/stancl/tenancy"><img alt="Latest Stable Version" src="https://poser.pugx.org/stancl/tenancy/version"></a> <a href="https://packagist.org/packages/stancl/tenancy"><img alt="Latest Stable Version" src="https://poser.pugx.org/stancl/tenancy/version"></a>
<a href="https://travis-ci.com/stancl/tenancy"><img alt="Travis CI build" src="https://travis-ci.com/stancl/tenancy.svg?branch=2.x"></a> <a href="https://github.com/stancl/tenancy/actions"><img alt="GitHub Actions CI status" src="https://github.com/stancl/tenancy/workflows/CI/badge.svg"></a>
<a href="https://codecov.io/gh/stancl/tenancy"><img alt="codecov" src="https://codecov.io/gh/stancl/tenancy/branch/2.x/graph/badge.svg"></a> <a href="https://codecov.io/gh/stancl/tenancy"><img alt="codecov" src="https://codecov.io/gh/stancl/tenancy/branch/2.x/graph/badge.svg"></a>
<a href="https://github.com/stancl/tenancy/blob/2.x/DONATIONS.md"><img alt="Donate" src="https://img.shields.io/badge/Donate-%3C3-red"></a> <a href="https://github.com/stancl/tenancy/blob/2.x/DONATIONS.md"><img alt="Donate" src="https://img.shields.io/badge/Donate-%3C3-red"></a>
</p> </p>
<h1><a href="https://tenancy.samuelstancl.me">stancl/tenancy</a></h1> <h1><a href="https://tenancyforlaravel.com">Tenancy for Laravel &mdash; stancl/tenancy</a></h1>
### *Automatic multi-tenancy for your Laravel app.* ### *Automatic multi-tenancy for your Laravel app.*
@ -20,9 +20,9 @@ You won't have to change a thing in your application's code.
- :heavy_check_mark: No replacing of Laravel classes (`Cache`, `Storage`, ...) with tenancy-aware classes - :heavy_check_mark: No replacing of Laravel classes (`Cache`, `Storage`, ...) with tenancy-aware classes
- :heavy_check_mark: Built-in tenant identification based on hostname (including second level domains) - :heavy_check_mark: Built-in tenant identification based on hostname (including second level domains)
### [Documentation](https://tenancy.samuelstancl.me/docs/v2/) ### [Documentation](https://tenancyforlaravel.com/docs/v2/)
Documentation can be found here: https://tenancy.samuelstancl.me/docs/v2/ Documentation can be found here: https://tenancyforlaravel.com/docs/v2/
The repository with the documentation source code can be found here: [stancl/tenancy-docs](https://github.com/stancl/tenancy-docs). The repository with the documentation source code can be found here: [stancl/tenancy-docs](https://github.com/stancl/tenancy-docs).
@ -30,5 +30,5 @@ The repository with the documentation source code can be found here: [stancl/ten
### Credits ### Credits
- Created by [Samuel Štancl](https://github.com/stancl) - Created by [Samuel Štancl](https://twitter.com/samuelstancl)
- Logo by [Caneco](https://twitter.com/caneco) - Logo by [Brian Dillingham](https://twitter.com/dillinghammm)

View file

@ -2,6 +2,8 @@
If you need help with implementing the package, you can: If you need help with implementing the package, you can:
- Open an [issue here on GitHub](https://github.com/stancl/tenancy/issues/new?assignees=stancl&labels=support&template=support-question.md&title=) - Open an [issue here on GitHub](https://github.com/stancl/tenancy/issues/new?assignees=stancl&labels=support&template=support-question.md&title=)
- Message me (`@stancl`) on the [Unofficial Laravel Discord](https://discord.gg/zGVGFAd), in the `#stancl_tenancy` channel - Join our new [Discord server](https://discord.gg/7cpgPxv) and ask in `#help`
The methods above are preferred, but you may also
- Contact me on Telegram: [@samuelstancl](https://t.me/samuelstancl) - Contact me on Telegram: [@samuelstancl](https://t.me/samuelstancl)
- Send me an email: [samuel.stancl@gmail.com](mailto:samuel.stancl@gmail.com) - Send me an email: [samuel.stancl@gmail.com](mailto:samuel.stancl@gmail.com)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 495 KiB

Before After
Before After

BIN
art/old_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View file

@ -3,112 +3,286 @@
declare(strict_types=1); declare(strict_types=1);
return [ return [
/**
* Storage drivers are used to store information about your tenants.
* They hold the Tenant Storage data and keeps track of domains.
*/
'storage_driver' => 'db', 'storage_driver' => 'db',
'storage_drivers' => [ 'storage_drivers' => [
/**
* The majority of applications will want to use this storage driver.
* The information about tenants is persisted in a relational DB
* like MySQL or PostgreSQL. The only downside is performance.
*
* A database connection to the central database has to be established on each
* request, to identify the tenant based on the domain. This takes three DB
* queries. Then, the connection to the tenant database is established.
*
* Note: From v2.3.0, the performance of the DB storage driver can be improved
* by a lot by using Cached Tenant Lookup. Be sure to enable that if you're
* using this storage driver. Enabling that feature can completely avoid
* querying the central database to identify build the Tenant object.
*/
'db' => [ 'db' => [
'driver' => Stancl\Tenancy\StorageDrivers\Database\DatabaseStorageDriver::class, 'driver' => Stancl\Tenancy\StorageDrivers\Database\DatabaseStorageDriver::class,
'data_column' => 'data', 'data_column' => 'data',
'custom_columns' => [ 'custom_columns' => [
// 'plan', // 'plan',
], ],
'connection' => null, // Your central database connection. Set to null to use the default connection.
/**
* Your central database connection. Set to null to use the default one.
*
* Note: It's recommended to create a designated central connection,
* to let you easily use it in your app, e.g. via the DB facade.
*/
'connection' => null,
'table_names' => [ 'table_names' => [
'tenants' => 'tenants', 'tenants' => 'tenants',
'domains' => 'domains', 'domains' => 'domains',
], ],
'cache_store' => null, // What store should be used to cache tenant resolution. Set to null to disable cache or a string with a specific cache store name.
/**
* Here you can enable the Cached Tenant Lookup.
*
* You can specify what cache store should be used to cache the tenant resolution.
* Set to string with a specific cache store name, or to null to disable cache.
*/
'cache_store' => null,
'cache_ttl' => 3600, // seconds 'cache_ttl' => 3600, // seconds
], ],
/**
* The Redis storage driver is much more performant than the database driver.
* However, by default, Redis is a not a durable data storage. It works well for ephemeral data
* like cache, but to hold critical data, it needs to be configured in a way that guarantees
* that data will be persisted permanently. Specifically, you want to enable both AOF and
* RDB. Read this here: https://tenancy.samuelstancl.me/docs/v2/storage-drivers/#redis.
*/
'redis' => [ 'redis' => [
'driver' => Stancl\Tenancy\StorageDrivers\RedisStorageDriver::class, 'driver' => Stancl\Tenancy\StorageDrivers\RedisStorageDriver::class,
'connection' => 'tenancy', 'connection' => 'tenancy',
], ],
], ],
/**
* Controller namespace used by routes in routes/tenant.php.
*/
'tenant_route_namespace' => 'App\Http\Controllers', 'tenant_route_namespace' => 'App\Http\Controllers',
'exempt_domains' => [ // e.g. domains which host landing pages, sign up pages, etc
/**
* Central domains (hostnames), e.g. domains which host landing pages, sign up pages, etc.
*/
'exempt_domains' => [
// 'localhost', // 'localhost',
], ],
'database' => [
'based_on' => null, // The connection that will be used as a base for the dynamically created tenant connection. Set to null to use the default connection. /**
'prefix' => 'tenant', * Tenancy bootstrappers are executed when tenancy is initialized.
'suffix' => '' * Their responsibility is making Laravel features tenant-aware.
], *
'redis' => [ * To configure their behavior, see the config keys below.
'prefix_base' => 'tenant', */
'prefixed_connections' => [
// 'default',
],
],
'cache' => [
'tag_base' => 'tenant',
],
'filesystem' => [ // https://tenancy.samuelstancl.me/docs/v2/filesystem-tenancy/
'suffix_base' => 'tenant',
'suffix_storage_path' => true, // Note: Disabling this will likely break local disk tenancy. Only disable this if you're using an external file storage service like S3.
'asset_helper_tenancy' => true, // should asset() be automatically tenant-aware. You may want to disable this if you use tools like Horizon.
// Disks which should be suffixed with the suffix_base + tenant id.
'disks' => [
'local',
'public',
// 's3',
],
'root_override' => [
// Disks whose roots should be overriden after storage_path() is suffixed.
'local' => '%storage_path%/app/',
'public' => '%storage_path%/app/public/',
],
],
'database_managers' => [
// Tenant database managers handle the creation & deletion of tenant databases.
'sqlite' => Stancl\Tenancy\TenantDatabaseManagers\SQLiteDatabaseManager::class,
'mysql' => Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager::class,
'pgsql' => Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLDatabaseManager::class,
// 'pgsql' => Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLSchemaManager::class, // Separate by schema instead of database
],
'database_manager_connections' => [
// Connections used by TenantDatabaseManagers. This tells, for example, the
// MySQLDatabaseManager to use the mysql connection to create databases.
'sqlite' => 'sqlite',
'mysql' => 'mysql',
'pgsql' => 'pgsql',
],
'bootstrappers' => [ 'bootstrappers' => [
// Tenancy bootstrappers are executed when tenancy is initialized.
// Their responsibility is making Laravel features tenant-aware.
'database' => Stancl\Tenancy\TenancyBootstrappers\DatabaseTenancyBootstrapper::class, 'database' => Stancl\Tenancy\TenancyBootstrappers\DatabaseTenancyBootstrapper::class,
'cache' => Stancl\Tenancy\TenancyBootstrappers\CacheTenancyBootstrapper::class, 'cache' => Stancl\Tenancy\TenancyBootstrappers\CacheTenancyBootstrapper::class,
'filesystem' => Stancl\Tenancy\TenancyBootstrappers\FilesystemTenancyBootstrapper::class, 'filesystem' => Stancl\Tenancy\TenancyBootstrappers\FilesystemTenancyBootstrapper::class,
'queue' => Stancl\Tenancy\TenancyBootstrappers\QueueTenancyBootstrapper::class, 'queue' => Stancl\Tenancy\TenancyBootstrappers\QueueTenancyBootstrapper::class,
// 'redis' => Stancl\Tenancy\TenancyBootstrappers\RedisTenancyBootstrapper::class, // Note: phpredis is needed // 'redis' => Stancl\Tenancy\TenancyBootstrappers\RedisTenancyBootstrapper::class, // Note: phpredis is needed
], ],
'features' => [
// Features are classes that provide additional functionality
// not needed for tenancy to be bootstrapped. They are run
// regardless of whether tenancy has been initialized.
// Stancl\Tenancy\Features\Timestamps::class, /**
// Stancl\Tenancy\Features\TenantConfig::class, * Database tenancy config. Used by DatabaseTenancyBootstrapper.
// Stancl\Tenancy\Features\TelescopeTags::class, */
// Stancl\Tenancy\Features\TenantRedirect::class, 'database' => [
/**
* The connection that will be used as a template for the dynamically created tenant connection.
* Set to null to use the default connection.
*/
'based_on' => null,
/**
* Tenant database names are created like this:
* prefix + tenant_id + suffix.
*/
'prefix' => 'tenant',
'suffix' => '',
],
/**
* Redis tenancy config. Used by RedisTenancyBoostrapper.
*
* Note: You need phpredis to use Redis tenancy.
*
* Note: You don't need to use this if you're using Redis only for cache.
* Redis tenancy is only relevant if you're making direct Redis calls,
* either using the Redis facade or by injecting it as a dependency.
*/
'redis' => [
'prefix_base' => 'tenant', // Each key in Redis will be prepended by this prefix_base, followed by the tenant id.
'prefixed_connections' => [ // Redis connections whose keys are prefixed, to separate one tenant's keys from another.
// 'default',
],
],
/**
* Cache tenancy config. Used by CacheTenancyBootstrapper.
*
* This works for all Cache facade calls, cache() helper
* calls and direct calls to injected cache stores.
*
* Each key in cache will have a tag applied on it. This tag is used to
* scope the cache both when writing to it and when reading from it.
*/
'cache' => [
'tag_base' => 'tenant', // This tag_base, followed by the tenant_id, will form a tag that will be applied on each cache call.
],
/**
* Filesystem tenancy config. Used by FilesystemTenancyBootstrapper.
* https://tenancy.samuelstancl.me/docs/v2/filesystem-tenancy/.
*/
'filesystem' => [
/**
* Each disk listed in the 'disks' array will be suffixed by the suffix_base, followed by the tenant_id.
*/
'suffix_base' => 'tenant',
'disks' => [
'local',
'public',
// 's3',
],
/**
* Use this for local disks.
*
* See https://tenancy.samuelstancl.me/docs/v2/filesystem-tenancy/
*/
'root_override' => [
// Disks whose roots should be overriden after storage_path() is suffixed.
'local' => '%storage_path%/app/',
'public' => '%storage_path%/app/public/',
],
/**
* Should storage_path() be suffixed.
*
* Note: Disabling this will likely break local disk tenancy. Only disable this if you're using an external file storage service like S3.
*
* For the vast majority of applications, this feature should be enabled. But in some
* edge cases, it can cause issues (like using Passport with Vapor - see #196), so
* you may want to disable this if you are experiencing these edge case issues.
*/
'suffix_storage_path' => true,
/**
* By default, asset() calls are made multi-tenant too. You can use global_asset() and mix()
* for global, non-tenant-specific assets. However, you might have some issues when using
* packages that use asset() calls inside the tenant app. To avoid such issues, you can
* disable asset() helper tenancy and explicitly use tenant_asset() calls in places
* where you want to use tenant-specific assets (product images, avatars, etc).
*/
'asset_helper_tenancy' => true,
],
/**
* TenantDatabaseManagers are classes that handle the creation & deletion of tenant databases.
*/
'database_managers' => [
'sqlite' => Stancl\Tenancy\TenantDatabaseManagers\SQLiteDatabaseManager::class,
'mysql' => Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager::class,
'pgsql' => Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLDatabaseManager::class,
/**
* Disable the pgsql manager above, enable the one below, and set the
* tenancy.database.separate_by config key to 'schema' if you would
* like to separate tenant DBs by schemas rather than databases.
*/
// 'pgsql' => Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLSchemaManager::class, // Separate by schema instead of database
],
/**
* Connections used by TenantDatabaseManagers. This tells, for example, the
* MySQLDatabaseManager to use the mysql connection to create databases.
*/
'database_manager_connections' => [
'sqlite' => 'sqlite',
'mysql' => 'mysql',
'pgsql' => 'pgsql',
],
/**
* Features are classes that provide additional functionality
* not needed for tenancy to be bootstrapped. They are run
* regardless of whether tenancy has been initialized.
*
* See the documentation page for each class to
* understand which ones you want to enable.
*/
'features' => [
// Stancl\Tenancy\Features\Timestamps::class, // https://tenancy.samuelstancl.me/docs/v2/features/timestamps/
// Stancl\Tenancy\Features\TenantConfig::class, // https://tenancy.samuelstancl.me/docs/v2/features/tenant-config/
// Stancl\Tenancy\Features\TelescopeTags::class, // https://tenancy.samuelstancl.me/docs/v2/telescope/
// Stancl\Tenancy\Features\TenantRedirect::class, // https://tenancy.samuelstancl.me/docs/v2/features/tenant-redirect/
], ],
'storage_to_config_map' => [ // Used by the TenantConfig feature 'storage_to_config_map' => [ // Used by the TenantConfig feature
// 'paypal_api_key' => 'services.paypal.api_key', // 'paypal_api_key' => 'services.paypal.api_key',
], ],
/**
* The URL to which users will be redirected when they try to acceess a central route on a tenant domain.
*/
'home_url' => '/app', 'home_url' => '/app',
/**
* Automatically create a database when creating a tenant.
*/
'create_database' => true, 'create_database' => true,
/**
* Should tenant databases be created asynchronously in a queued job.
*/
'queue_database_creation' => false, 'queue_database_creation' => false,
'migrate_after_creation' => false, // run migrations after creating a tenant
/**
* Should tenant migrations be ran after the tenant's database is created.
*/
'migrate_after_creation' => false,
'migration_parameters' => [ 'migration_parameters' => [
// '--force' => true, // force database migrations // '--force' => true, // Set this to true to be able to run migrations in production
// '--path' => [], // If you need to customize paths to tenant migrations
], ],
/**
* Should tenant databases be automatically seeded after they're created & migrated.
*/
'seed_after_migration' => false, // should the seeder run after automatic migration 'seed_after_migration' => false, // should the seeder run after automatic migration
'seeder_parameters' => [ 'seeder_parameters' => [
'--class' => 'DatabaseSeeder', // root seeder class, e.g.: 'DatabaseSeeder' '--class' => 'DatabaseSeeder', // root seeder class, e.g.: 'DatabaseSeeder'
// '--force' => true, // force database seeder // '--force' => true,
], ],
/**
* Should tenant databases be deleted asynchronously in a queued job.
*/
'queue_database_deletion' => false, 'queue_database_deletion' => false,
'delete_database_after_tenant_deletion' => false, // delete the tenant's database after deleting the tenant
/**
* Automatically delete the tenant's database after the tenant is deleted.
*
* This will save space but permanently delete data which you might want to keep.
*/
'delete_database_after_tenant_deletion' => false,
/**
* If you don't supply an id when creating a tenant, this class will be used to generate a random ID.
*/
'unique_id_generator' => Stancl\Tenancy\UniqueIDGenerators\UUIDGenerator::class, 'unique_id_generator' => Stancl\Tenancy\UniqueIDGenerators\UUIDGenerator::class,
/**
* Middleware pushed to the global middleware stack.
*/
'global_middleware' => [ 'global_middleware' => [
Stancl\Tenancy\Middleware\InitializeTenancy::class, Stancl\Tenancy\Middleware\InitializeTenancy::class,
], ],

View file

@ -4,4 +4,4 @@ set -e
# for development # for development
docker-compose up -d docker-compose up -d
./test "$@" ./test "$@"
docker-compose exec test vendor/bin/phpcov merge --clover clover.xml coverage/ docker-compose exec -T test vendor/bin/phpcov merge --clover clover.xml coverage/

View file

@ -43,6 +43,12 @@ class Seed extends SeedCommand
*/ */
public function handle() public function handle()
{ {
foreach (config('tenancy.seeder_parameters') as $parameter => $value) {
if (! $this->input->hasParameterOption($parameter)) {
$this->input->setOption(ltrim($parameter, '-'), $value);
}
}
if (! $this->confirmToProceed()) { if (! $this->confirmToProceed()) {
return; return;
} }
@ -52,12 +58,6 @@ class Seed extends SeedCommand
$this->input->setOption('database', $tenant->getConnectionName()); $this->input->setOption('database', $tenant->getConnectionName());
foreach (config('tenancy.seeder_parameters') as $parameter => $value) {
if (! $this->input->hasParameterOption($parameter)) {
$this->input->setOption(ltrim($parameter, '-'), $value);
}
}
$tenant->run(function () { $tenant->run(function () {
// Seed // Seed
parent::handle(); parent::handle();

View file

@ -7,6 +7,7 @@ namespace Stancl\Tenancy\Features;
use Laravel\Telescope\IncomingEntry; use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope; use Laravel\Telescope\Telescope;
use Stancl\Tenancy\Contracts\Feature; use Stancl\Tenancy\Contracts\Feature;
use Stancl\Tenancy\Middleware\PreventAccessFromTenantDomains;
use Stancl\Tenancy\TenantManager; use Stancl\Tenancy\TenantManager;
class TelescopeTags implements Feature class TelescopeTags implements Feature
@ -30,7 +31,15 @@ class TelescopeTags implements Feature
Telescope::tag(function (IncomingEntry $entry) { Telescope::tag(function (IncomingEntry $entry) {
$tags = $this->getTags($entry); $tags = $this->getTags($entry);
if (in_array('tenancy', optional(request()->route())->middleware() ?? [])) { if (! request()->route()) {
return $tags;
}
$tenantRoute = PreventAccessFromTenantDomains::routeHasMiddleware(request()->route(), 'tenancy')
|| PreventAccessFromTenantDomains::routeHasMiddleware(request()->route(), 'universal');
// Don't do anything if we're visiting a universal route on a central domain
if ($tenantRoute && tenancy()->initialized) {
$tags = array_merge($tags, [ $tags = array_merge($tags, [
'tenant:' . tenant('id'), 'tenant:' . tenant('id'),
]); ]);

View file

@ -36,7 +36,7 @@ class InitializeTenancy
try { try {
tenancy()->init($request->getHost()); tenancy()->init($request->getHost());
} catch (TenantCouldNotBeIdentifiedException $e) { } catch (TenantCouldNotBeIdentifiedException $e) {
($this->onFail)($e); return ($this->onFail)($e, $request, $next);
} }
} }

View file

@ -41,7 +41,7 @@ class InitializeTenancyByRequestData
try { try {
$this->initializeTenancy($request); $this->initializeTenancy($request);
} catch (TenantCouldNotBeIdentifiedException $e) { } catch (TenantCouldNotBeIdentifiedException $e) {
($this->onFail)($e); return ($this->onFail)($e, $request, $next);
} }
} }

View file

@ -13,6 +13,16 @@ use Illuminate\Support\Facades\Route as Router;
*/ */
class PreventAccessFromTenantDomains class PreventAccessFromTenantDomains
{ {
/** @var callable */
protected $central404;
public function __construct(callable $central404 = null)
{
$this->central404 = $central404 ?? function () {
return 404;
};
}
/** /**
* Handle an incoming request. * Handle an incoming request.
* *
@ -39,13 +49,13 @@ class PreventAccessFromTenantDomains
} }
if ($isExemptDomain && $isTenantRoute) { // accessing tenant routes on web domains if ($isExemptDomain && $isTenantRoute) { // accessing tenant routes on web domains
abort(404); return ($this->central404)($request, $next);
} }
return $next($request); return $next($request);
} }
public function routeHasMiddleware(Route $route, $middleware): bool public static function routeHasMiddleware(Route $route, $middleware): bool
{ {
if (in_array($middleware, $route->middleware(), true)) { if (in_array($middleware, $route->middleware(), true)) {
return true; return true;

View file

@ -28,7 +28,7 @@ class CachedTenantResolver
return $this->config->get('tenancy.storage_drivers.db.cache_ttl'); return $this->config->get('tenancy.storage_drivers.db.cache_ttl');
} }
public function getTenantIdByDomain(string $domain, Closure $query): string public function getTenantIdByDomain(string $domain, Closure $query): ?string
{ {
return $this->cache->remember('_tenancy_domain_to_id:' . $domain, $this->ttl(), $query); return $this->cache->remember('_tenancy_domain_to_id:' . $domain, $this->ttl(), $query);
} }

View file

@ -14,14 +14,8 @@ trait TenantAwareCommand
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {
$tenants = $this->getTenants(); $tenants = $this->getTenants();
if (count($tenants) === 1) {
return $tenants[0]->run(function () {
return $this->laravel->call([$this, 'handle']);
});
}
$exitCode = 0; $exitCode = 0;
foreach ($tenants as $tenant) { foreach ($tenants as $tenant) {
$result = (int) $tenant->run(function () { $result = (int) $tenant->run(function () {
return $this->laravel->call([$this, 'handle']); return $this->laravel->call([$this, 'handle']);

4
test
View file

@ -2,6 +2,6 @@
set -e set -e
printf "Variant 1 (DB)\n\n" printf "Variant 1 (DB)\n\n"
docker-compose exec test env TENANCY_TEST_STORAGE_DRIVER=db vendor/bin/phpunit --coverage-php coverage/1.cov "$@" docker-compose exec -T test env TENANCY_TEST_STORAGE_DRIVER=db vendor/bin/phpunit --coverage-php coverage/1.cov "$@"
printf "Variant 2 (Redis)\n\n" printf "Variant 2 (Redis)\n\n"
docker-compose exec test env TENANCY_TEST_STORAGE_DRIVER=redis vendor/bin/phpunit --coverage-php coverage/2.cov "$@" docker-compose exec -T test env TENANCY_TEST_STORAGE_DRIVER=redis vendor/bin/phpunit --coverage-php coverage/2.cov "$@"