i have a working application, written in cakephp 4.4 and would like to implement a multi-tenant capability.
For this I have a database-table with the tenants, which always have a short name.
With a setting in the configuration I would switch on this multi-tenant mode.
The tenant, which is then used in the database queries, should be fetched from the URL, possibly via the routing settings.
In addition, I also have an API in the normal single tenant mode, accessible at https://domain.de/api/.
It is configured in the routes.php by using the prefix method.
The API should also be accessed here via /company1/api/users/…
The request object is then being passed down to the controller, which then can do its logic dependent on the information present in the request.
So you load the tenant entity (if available) in the custom middleware, set it as an attribute in the request and your controller actions can check if that custom request attribute is present and do their related logic dependent on that.
And a CustomHtml Helper, because the links are generated without a tenant by default:
class CustomHtmlHelper extends HtmlHelper
{
public function link($title, $url = null, array $options = []): string
{
// Prüfe, ob der Mandant in den URL-Parametern vorhanden ist
$tenant = $this->getView()->getRequest()->getParam('tenant');
if (!empty($tenant)) {
if(is_array($url)) {
// Füge den "mandant" als named Parameter hinzu
$url['tenant'] = $tenant;
} else {
// Füge den Mandant der URL bei einem String als Präfix an.
$url = $tenant . '/' . $url;
}
}
return parent::link($title, $url, $options);
}
}
In my request, I now get the “tenant” parameter, which I can use in the controller.
I get now several problems, e.g. in the login-method from the Authentication Plugin:
“Login URL /test/users/login did not match /users/login.”
You are the app developer and you have specific requirements for your multi-tenancy application.
The framework offers multiple different ways how you can approach your problems. There is no “single one way” to do things because 5 different approaches each have their own benefits and drawbacks.
We can’t tell you if its “the right way” because we are (and of course should not) be responsible for your app.
I really want and have to develop it exactly as described, maybe the tenant set by a subdomain, e.g. https://tenant.domain.de. The fact is, the URL must define which tenant-context I am in.
Apparently CakePHP does not provide this by default, so I’m asking if there is another solution or if I’m on the right track here and I just have to deal with the many sub-problems.
<?php
namespace Myplugin\Event;
use Cake\Event\EventListenerInterface;
use Cake\ORM\TableRegistry;
use Cake\Core\Configure;
use Cake\Log\Log;
class ArticleListener implements EventListenerInterface
{
public function implementedEvents() : array
{
return ['Model.Articles.afterCreate' => 'changeArticle'];
}
public function adjustArticle($event, $article)
{
......
}
}
This results in a missing route exception when you have this in config bootstrap in plugin
/* Register our Listeners */
use Cake\Event\EventManager;
use Myplugin\Event\ArticleListener;
$article = new ArticleListener();
EventManager::instance()->on($article);
Maybe not related to initial post but its also throwing the missing route exception when the error really is something totally different.