13. Request lifecycle
- Request
- Middleware
- Setup tenant connection
- Controller
- Call models from the tenant db
- Call models from a shared or master database
- Inter database relations
- Fire a tenant event
- Return response
22. Call model from the tenant db
- Primary connection
- Call model as normally
i.e.
- Model::find(1);
23. Call model from shared or master db
- Switch connection of a model or set the default connection on the model
- Retrieve the model using eloquent
24. Call model from shared or master db
class Permission extends Model
{
public function getConnectionName()
{
return 'shared_database';
}
protected $fillable = [
'name',
'description',
'policy'
];
}
Models/Permission.php
25. Inter database relations
- A Role has many Permissions
- Permissions are stored in shared db
- Laravel limitations and how to fix them
- Direction of relations
SELECT * FROM tenant_database.users AS u
JOIN tenant_database.users_roles AS ur ON u.id = ur.user_id
JOIN shared_database.roles AS r ON ur.role_id = r.id
WHERE u.id = 1;
26. Call model from shared or master db
class Permission extends Model
{
...
private function getTableNameForConnection($table, $connection = null)
{
return vsprintf('%s.%s', [$this->getDatabaseNameForConnection($connection), $table]);
}
public function roles()
{
return $this->belongsToMany(
AppModelsRole::class,
$this->getTableNameForConnection('role_permissions', 'tenant_database'),
'permission_id',
'role_id'
);
}
...
}
Models/Permission.php
27. Fire an event
- Only a problem on Async listeners
- Needs a tenant to run
28. Fire an event
abstract class TenantEvent extends Event
{
public function __construct()
{
if (($tenant = $this->getTenantService()->getTenant()) instanceof Tenant) {
$this->setTenant($tenant);
} else {
throw new MissingTenantException();
}
}
public function __sleep()
{
// Unset tenant model for serialization
$this->tenant = null;
// Continue with sleep
return parent::__sleep();
}
public function __wakeup()
{
// Fetch the tenant by id
$this->tenant = $this->getTenantService()->find($this->tenantId);
$this->tenantId = $this->tenant->id;
// Initialize tenant database connection
$this->getTenantManager()->connect($this->tenant);
// Continue with wake up
parent::__wakeup();
}
}
Abstracts/TenantEvent.php
29. Warnings
Everything outside the request lifecycle requires manual tenant switching
Cache
Broadcast
Storage
Queues
Inter database relations and connections to be used
Cross connection transactions
30. Pro’s & Con’s
Backups per tenant
Easy recovery
GDPR
Scalability
Manageability (migrating to new db environment)
Overhead
Complexer logic for built in laravel functions:
- Commands
- Events
- Queues
- Broadcasting
Planning ahead
32. Packages
I don’t want to do this all by myself:
https://github.com/hyn/multi-tenant ★1143
https://github.com/orchestral/tenanti ★406
https://github.com/HipsterJazzbo/Landlord ★525
33. Andere onderwerpen
● Laravel API's and their limitations
● Strangling Laravel with react
● Deploying Laravel to production (With CI)
● Error handling in Laravel with channels and sentry
● Oauth2 implementation with passport (and what its missing)
● Laravel and Kubernetes
● Local development with Docker
● Broadcasting to the world
● Storage in the cloud, and efficient image retrieval (Thumbor and S3)
● Unit testing, Integration testing, Browser testing
● Package development and contributing to open source
● Modular laravel; simulate microservices
https://sli.do #F294