diff --git a/.travis.yml b/.travis.yml
index 1433d9ac..88e84dda 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,18 @@
language: php
php:
- - '7.1'
- '7.2'
+ - '7.1'
branches:
only:
- master
+services:
+ - redis-server
+
+before_install:
+ - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
+
install:
- travis_retry composer install --no-interaction
diff --git a/README.md b/README.md
index 484c54bc..c05add20 100644
--- a/README.md
+++ b/README.md
@@ -393,3 +393,41 @@ Tenant migrations are located in `database/migrations/tenant`, so you should mov
## Some tips
- If you create a tenant using the interactive console (`artisan tinker`) and use sqlite, you might need to change the database's permissions and/or ownership (`chmod`/`chown`) so that the web application can access it.
+
+## HTTPS certificates
+
+HTTPS certificates are very easy to deal with if you use the `yourclient1.yourapp.com`, `yourclient2.yourapp.com` model. You can use a wildcard HTTPS certificate.
+
+If you use the model where second level domains are used, there are multiple ways you can solve this.
+
+This guide focuses on nginx.
+
+### 1. Use nginx with the lua module
+
+Specifically, you're interested in the [`ssl_certificate_by_lua_block`](https://github.com/openresty/lua-nginx-module#ssl_certificate_by_lua_block) directive. Nginx doesn't support using variables such as the hostname in the `ssl_certificate` directive, which is why the lua module is needed.
+
+This approach lets you use one server block for all tenants.
+
+### 2. Add a simple server block for each tenant
+
+You can store most of your config in a file, such as `/etc/nginx/includes/tenant`, and include this file into tenant server blocks.
+
+```nginx
+server {
+ include includes/tenant;
+ server_name foo.bar;
+ # ssl_certificate /etc/foo/...;
+}
+```
+
+### Generating certificates
+
+You can generate a certificate using certbot. If you use the `--nginx` flag, you will need to run certbot as root. If you use the `--webroot` flag, you only need the user that runs it to have write access to the webroot directory (or perhaps webroot/.well-known is enough) and some certbot files (you can specify these using --work-dir, --config-dir and --logs-dir).
+
+Creating this config dynamically from PHP is not easy, but is probably feasible. Giving `www-data` write access to `/etc/nginx/sites-available/tenants.conf` should work.
+
+However, you still need to reload nginx configuration to apply the changes to configuration. This is problematic and I'm not sure if there is a simple and secure way to do this from PHP.
+
+## Testing
+
+If you run the tests of this package, please make sure you don't store anything in Redis @ 127.0.0.1:6379 db#14. The contents of this database are flushed everytime the tests are run.
diff --git a/phpunit.xml b/phpunit.xml
index 2e630c0b..da25c19f 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -15,7 +15,10 @@
- ./app
+ ./src
+
+ ./src/routes.php
+
diff --git a/src/DatabaseManager.php b/src/DatabaseManager.php
index 745efddf..f30025fe 100644
--- a/src/DatabaseManager.php
+++ b/src/DatabaseManager.php
@@ -44,6 +44,11 @@ class DatabaseManager
return DB::statement("CREATE DATABASE `$name` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
}
+ public function delete()
+ {
+ // todo: delete database. similar to create()
+ }
+
public function getDriver(): ?string
{
return config("database.connections.tenant.driver");
diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php
index 678ebe24..f613184b 100644
--- a/src/TenancyServiceProvider.php
+++ b/src/TenancyServiceProvider.php
@@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
use Stancl\Tenancy\Commands\TenantList;
use Stancl\Tenancy\Interfaces\StorageDriver;
+use Stancl\Tenancy\Interfaces\ServerConfigManager;
use Stancl\Tenancy\StorageDrivers\RedisStorageDriver;
class TenancyServiceProvider extends ServiceProvider
@@ -54,6 +55,7 @@ class TenancyServiceProvider extends ServiceProvider
$this->mergeConfigFrom(__DIR__ . '/config/tenancy.php', 'tenancy');
$this->app->bind(StorageDriver::class, $this->app['config']['tenancy.storage_driver']);
+ $this->app->bind(ServerConfigManager::class, $this->app['config']['tenancy.server.manager']);
$this->app->singleton(DatabaseManager::class);
$this->app->singleton(TenantManager::class, function ($app) {
return new TenantManager($app, $app[StorageDriver::class], $app[DatabaseManager::class]);
diff --git a/src/TenantManager.php b/src/TenantManager.php
index 75568367..57c66c04 100644
--- a/src/TenantManager.php
+++ b/src/TenantManager.php
@@ -2,9 +2,9 @@
namespace Stancl\Tenancy;
-use Stancl\Tenancy\BootstrapsTenancy;
use Illuminate\Support\Facades\Redis;
use Stancl\Tenancy\Interfaces\StorageDriver;
+use Stancl\Tenancy\Traits\BootstrapsTenancy;
class TenantManager
{
@@ -77,7 +77,7 @@ class TenantManager
throw new \Exception("Domain $domain is already occupied by tenant $id.");
}
- $tenant = $this->storage->createTenant($domain, \Uuid::generate(1, $domain));
+ $tenant = $this->storage->createTenant($domain, \Webpatser\Uuid\Uuid::generate(1, $domain));
$this->database->create($this->getDatabaseName($tenant));
return $tenant;
@@ -264,4 +264,19 @@ class TenantManager
return $this->put($this->put($key, $value));
}
+
+ /**
+ * Return the identified tenant's attribute(s).
+ *
+ * @param string $attribute
+ * @return mixed
+ */
+ public function __invoke($attribute)
+ {
+ if (is_null($attribute)) {
+ return $this->tenant;
+ }
+
+ return $this->tenant[(string) $attribute];
+ }
}
diff --git a/src/Traits/BootstrapsTenancy.php b/src/Traits/BootstrapsTenancy.php
index 1775fc15..a791854a 100644
--- a/src/Traits/BootstrapsTenancy.php
+++ b/src/Traits/BootstrapsTenancy.php
@@ -1,6 +1,9 @@
tenant['uuid'];
$client = Redis::connection($connection)->client();
diff --git a/tests/TestCase.php b/tests/TestCase.php
index a33d3ad7..1a29c5b8 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -2,6 +2,8 @@
namespace Stancl\Tenancy\Tests;
+use Illuminate\Support\Facades\Redis;
+
class TestCase extends \Orchestra\Testbench\TestCase
{
/**
@@ -13,7 +15,35 @@ class TestCase extends \Orchestra\Testbench\TestCase
{
parent::setUp();
- //
+ Redis::connection('tenancy')->flushdb();
+
+ tenant()->create('localhost');
+
+ tenancy()->init('localhost');
+ }
+
+ /**
+ * Define environment setup.
+ *
+ * @param \Illuminate\Foundation\Application $app
+ * @return void
+ */
+ protected function getEnvironmentSetUp($app)
+ {
+ $app['config']->set('database.redis.client', 'phpredis');
+ $app['config']->set('database.redis.tenancy', [
+ 'host' => env('TENANCY_TEST_REDIS_HOST', '127.0.0.1'),
+ 'password' => env('TENANCY_TEST_REDIS_PASSWORD', null),
+ 'port' => env('TENANCY_TEST_REDIS_PORT', 6379),
+ // Use the #14 Redis database unless specified otherwise.
+ // Make sure you don't store anything in this db!
+ 'database' => env('TENANCY_TEST_REDIS_DB', 14),
+ ]);
+ $app['config']->set('tenancy.database', [
+ 'based_on' => 'sqlite',
+ 'prefix' => 'tenant',
+ 'suffix' => '.sqlite',
+ ]);
}
protected function getPackageProviders($app)