I'm trying to create roles and permissions for Central and the Tenants, but when creating the tenant itself I get this error
There is no permission named surveys-read for guard admin.
It's correct but there shouldn't be one, that's the problem. The surveys-read permission is for the tenants using guard web and not for central users. the code fails on $tenant->save()
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string',
'description' => 'nullable|string',
'domain' => 'required|alpha_dash|unique:domains,domain',
'tenancy_db_name' => 'required|alpha_dash',
'color_logo' => 'required',
'white_logo' => 'required',
'gps_token' => 'required'
]);
$databaseNameExist = Tenant::all()
->where('tenancy_db_name', $validated['tenancy_db_name']);
if ($databaseNameExist->count() > 0) {
throw ValidationException::withMessages(['El nombre de la base de datos ya se encuentra registrado']);
}
$tenant = new Tenant();
$tenant->fill($validated);
$tenant->color_logo = request()->file('color_logo')->store('logos', 'public');
$tenant->white_logo = request()->file('white_logo')->store('logos', 'public');
$tenant->save();
$domain = $validated['domain'] . '.' . $_SERVER['SERVER_NAME'];
Domain::updateOrCreate(
[ tenant_id' => $tenant->id ],
[ 'domain' => $domain ]
);
return Redirect::route('home')->with('success', 'El Cliente ha sido creado.');
}
They have this in their docs https://tenancyforlaravel.com/docs/v3/integrations/spatie/
But it doesn't work, I get a different error. This error covers the entire page and I can't do anything.
Object of class Closure could not be converted to string
It points to the method bootEvents in TenancyServiceProvider.php
<?php
declare(strict_types=1);
namespace App\Providers;
use App\Jobs\CreateFrameworkDirectoriesForTenant;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
use Spatie\Permission\PermissionRegistrar;
use Stancl\JobPipeline\JobPipeline;
use Stancl\Tenancy\Events;
use Stancl\Tenancy\Jobs;
use Stancl\Tenancy\Listeners;
use Stancl\Tenancy\Middleware;
class TenancyServiceProvider extends ServiceProvider
{
// By default, no namespace is used to support the callable array syntax.
public static string $controllerNamespace = '';
public function events()
{
return [
// Tenant events
Events\CreatingTenant::class => [],
Events\TenantCreated::class => [
JobPipeline::make([
Jobs\CreateDatabase::class,
Jobs\MigrateDatabase::class,
Jobs\SeedDatabase::class,
// Your own jobs to prepare the tenant.
// Provision API keys, create S3 buckets, anything you want!
CreateFrameworkDirectoriesForTenant::class
])->send(function (Events\TenantCreated $event) {
return $event->tenant;
})->shouldBeQueued(true), // `false` by default, but you probably want to make this `true` for production.
],
Events\SavingTenant::class => [],
Events\TenantSaved::class => [],
Events\UpdatingTenant::class => [],
Events\TenantUpdated::class => [],
Events\DeletingTenant::class => [],
Events\TenantDeleted::class => [
JobPipeline::make([
Jobs\DeleteDatabase::class,
])->send(function (Events\TenantDeleted $event) {
return $event->tenant;
})->shouldBeQueued(true), // `false` by default, but you probably want to make this `true` for production.
],
// Domain events
Events\CreatingDomain::class => [],
Events\DomainCreated::class => [],
Events\SavingDomain::class => [],
Events\DomainSaved::class => [],
Events\UpdatingDomain::class => [],
Events\DomainUpdated::class => [],
Events\DeletingDomain::class => [],
Events\DomainDeleted::class => [],
// Database events
Events\DatabaseCreated::class => [],
Events\DatabaseMigrated::class => [],
Events\DatabaseSeeded::class => [],
Events\DatabaseRolledBack::class => [],
Events\DatabaseDeleted::class => [],
// Tenancy events
Events\InitializingTenancy::class => [],
Events\TenancyInitialized::class => [
Listeners\BootstrapTenancy::class,
],
Events\EndingTenancy::class => [],
Events\TenancyEnded::class => [
Listeners\RevertToCentralContext::class,
function (Events\TenancyEnded $event) {
\Spatie\Permission\PermissionRegistrar::$cacheKey = 'spatie.permission.cache';
},
],
Events\BootstrappingTenancy::class => [],
Events\TenancyBootstrapped::class => [
function (Events\TenancyBootstrapped $event) {
\Spatie\Permission\PermissionRegistrar::$cacheKey = 'spatie.permission.cache.tenant.' . $event->tenancy->tenant->id;
}
],
Events\RevertingToCentralContext::class => [],
Events\RevertedToCentralContext::class => [],
// Resource syncing
Events\SyncedResourceSaved::class => [
Listeners\UpdateSyncedResource::class,
],
// Fired only when a synced resource is changed in a different DB than the origin DB (to avoid infinite loops)
Events\SyncedResourceChangedInForeignDatabase::class => [],
];
}
public function register()
{
//
}
public function boot()
{
$this->bootEvents();
$this->mapRoutes();
$this->makeTenancyMiddlewareHighestPriority();
}
protected function bootEvents() //THIS METHOD
{
foreach ($this->events() as $event => $listeners) {
foreach (array_unique($listeners) as $listener) { //THIS LINE
if ($listener instanceof JobPipeline) {
$listener = $listener->toListener();
}
Event::listen($event, $listener);
}
}
}
protected function mapRoutes()
{
if (file_exists(base_path('routes/tenant.web.php'))) {
Route::middleware('tenant')
->namespace(static::$controllerNamespace)
->group(base_path('routes/tenant.web.php'));
}
if (file_exists(base_path('routes/tenant.api.php'))) {
Route::middleware('tenant')
->namespace(static::$controllerNamespace)
->group(base_path('routes/tenant.api.php'));
}
}
protected function makeTenancyMiddlewareHighestPriority()
{
$tenancyMiddleware = [
// Even higher priority than the initialization middleware
Middleware\PreventAccessFromCentralDomains::class,
Middleware\InitializeTenancyByDomain::class,
Middleware\InitializeTenancyBySubdomain::class,
Middleware\InitializeTenancyByDomainOrSubdomain::class,
Middleware\InitializeTenancyByPath::class,
Middleware\InitializeTenancyByRequestData::class,
];
foreach (array_reverse($tenancyMiddleware) as $middleware) {
$this->app[\Illuminate\Contracts\Http\Kernel::class]->prependToMiddlewarePriority($middleware);
}
}
}
What am I doing wrong?