Hi @alex
Thanks for being an amazing tutor, and i'm glad i subscribed to this website.
I have a problem with one of your course which is here https://codecourse.com/watch/laravel-multi-tenancy-basics?part=tenant-registration the problem has to do with validation. I am trying to validate unique email and also unique username for newly registered tenant from central domain.
My code looks like this
return [
'username' => ['required', 'alpha_dash', 'string', 'max:40', 'without_spaces'],
'email' => ['required', 'string', 'email', 'max:255', Rule::unique('users', 'email')->where('tenant_id', tenant('id'))],
// 'email' => $tenant->unique('users'),
'domain' => ['required', 'string', 'max:255', 'unique:domains'],
'password' => ['required', Rules\Password::min(8)
->mixedCase()
->letters()
->numbers()
->symbols()],
'username.without_spaces' => 'Whitespace not allowed.'
];
and i get this error
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'tenancy.users' doesn't exist
How do i solve this please
Hmm, this should work because you're scoping to the current tenant. Is the controller that you're validating in under the tenant group in your routes? Might be worth posting those too.
Hi @alex,
Thanks for your response
i have this in my controller
public function store(RegisterTenantRequest $request)
{
$tenant = Tenant::create($request->validated());
$tenant->createDomain(['domain' => $request->domain]);
}
i have this in my user model
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Stancl\Tenancy\Database\Concerns\HasScopedValidationRules;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable, HasScopedValidationRules;
and this in my Tenant model
use Stancl\Tenancy\Database\Models\Tenant as BaseTenant;
use Stancl\Tenancy\Contracts\TenantWithDatabase;
use Stancl\Tenancy\Database\Concerns\HasDatabase;
use Stancl\Tenancy\Database\Concerns\HasDomains;
use Stancl\Tenancy\Database\Concerns\HasScopedValidationRules;
class Tenant extends BaseTenant implements TenantWithDatabase
{
use HasDatabase, HasDomains, HasScopedValidationRules;
and this in my user schema
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->string('name')->nullable();
$table->string('email')->unique();
$table->string('username')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
$table->foreign('tenant_id')->references('id')->on('tenants')->onDelete('cascade');
});
}
Looking forward to your response
Thanks for the additional code. Are you trying to do something differently to the course? With the initial tenant registration, this should happen in the tenants table of the main central application database.
Let me know if your code is hosted somewhere too, like GitHub, so I can have a really good look.
Tenancy is difficult!
Hi @alex thanks again for replying.
You know in the video we create a tenant and also register main user for the tenant.
What i am trying to do is validate the email and username of the users so that a user that sign up with the registration form can't sign up again with same email and username but different domain.
Here is my github linkhttps://github.com/oladejihenry/multi
Thanks, I'll take a look at it over the next day or so for you!
Hi @alex
I was able to solve this by adding the HasScopedValidationRules to my Tenant model and did the following below also in the Tenant Model
protected $rules;
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->rules = [
'email' => ['required', 'email', Rule::unique('tenants')->whereNull('deleted_at')],
// Other validation rules for the Tenant model here
];
}
Then i created a validation rules and i have this in it
public function passes($attribute, $value)
{
// Check if the email address is unique among tenants (within the JSON data)
return !DB::table('tenants')->whereJsonContains('data->email', $value)->exists();
}
public function message()
{
return 'This email address has already been taken by another tenant.';
}
Then passed that into my form request validation as this 'email' => ['required', 'string', 'email', 'max:255', new UniqueEmailForTenant],
Then it works by checking if an email is already taken by a tenant and pass the validation message to them
What do you think??