Skip to content

Commit

Permalink
added multi-tenancy
Browse files Browse the repository at this point in the history
  • Loading branch information
Flatroy committed Jun 18, 2024
1 parent dd8ad06 commit e467f5e
Show file tree
Hide file tree
Showing 14 changed files with 289 additions and 9 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ WIP
- [ ] Add attachments to items - https://filamentphp.com/plugins/filament-spatie-media-library
- [ ] Show related items in Location view - https://filamentphp.com/docs/3.x/panels/resources/relation-managers#creating-a-relation-manager
- [ ] Add QR code to items
- [ ] Add multi-tenancy support - https://filamentphp.com/docs/3.x/panels/tenancy
- [x] Add multi-tenancy support - https://filamentphp.com/docs/3.x/panels/tenancy
- [ ] Add better import/export of items with relation to locations
- [ ] Add Laravel Octane
- [ ] Add Laravel Pulse


## Contributing

Thank you for considering contributing to the project! All contributions are welcome.
Thank you for choosing to contribute to the project! Any contribution is welcome.
19 changes: 19 additions & 0 deletions app/Filament/Pages/Auth/Login.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace App\Filament\Pages\Auth;

use Filament\Pages\Auth\Login as BasePage;

class Login extends BasePage
{
public function mount(): void
{
parent::mount();

$this->form->fill([
'email' => '[email protected]',
'password' => 'password',
'remember' => true,
]);
}
}
24 changes: 24 additions & 0 deletions app/Filament/Pages/Tenancy/EditTeamProfile.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace App\Filament\Pages\Tenancy;

use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\Tenancy\EditTenantProfile;

class EditTeamProfile extends EditTenantProfile
{
public static function getLabel(): string
{
return 'Team profile';
}

public function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')->required(),
// ...
]);
}
}
23 changes: 23 additions & 0 deletions app/Filament/Pages/Tenancy/RegisterTeam.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace App\Filament\Pages\Tenancy;

use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\Tenancy\RegisterTenant;

class RegisterTeam extends RegisterTenant
{
public static function getLabel(): string
{
return 'New team';
}

public function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')->required(),
]);
}
}
16 changes: 15 additions & 1 deletion app/Filament/Resources/ItemResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,21 @@ public static function form(Form $form): Form
->createOptionForm([
TextInput::make('name')
->required(),
Textarea::make('description')->columnSpanFull()->rows(3)->autosize(),

Textarea::make('description')
->columnSpanFull()
->rows(3)
->autosize(),

Select::make('parent_id')
->label('Parent Location')
->relationship(
name: 'parent',
titleAttribute: 'name',
ignoreRecord: true
)
->preload()
->searchable(),
])
->preload()
->searchable()
Expand Down
25 changes: 22 additions & 3 deletions app/Filament/Resources/LocationResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;

Expand All @@ -36,11 +35,31 @@ public static function form(Form $form): Form
->required(),

Select::make('parent_id')->label('Parent Location')
->relationship(name: 'parent', titleAttribute: 'name', ignoreRecord: true)
->relationship(
name: 'parent',
titleAttribute: 'name',
ignoreRecord: true
)
->preload()
->searchable()
->createOptionForm([
TextInput::make('name')
->required(),
Textarea::make('description')->columnSpanFull()->rows(3)->autosize(),

Textarea::make('description')
->columnSpanFull()
->rows(3)
->autosize(),

Select::make('parent_id')
->label('Parent Location')
->relationship(
name: 'parent',
titleAttribute: 'name',
ignoreRecord: true
)
->preload()
->searchable(),
]),

Textarea::make('description')->columnSpanFull()->rows(3)->autosize(),
Expand Down
31 changes: 31 additions & 0 deletions app/Http/Middleware/ApplyTenantScopes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace App\Http\Middleware;

use App\Models\Item;
use App\Models\Location;
use Closure;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class ApplyTenantScopes
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
Location::addGlobalScope(
fn (Builder $query) => $query->whereBelongsTo(Filament::getTenant()),
);
Item::addGlobalScope(
fn (Builder $query) => $query->whereBelongsTo(Filament::getTenant()),
);

return $next($request);
}
}
10 changes: 10 additions & 0 deletions app/Models/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Models;

use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
Expand Down Expand Up @@ -36,6 +37,7 @@ class Item extends Model
'sold_price',
'sold_notes',
'location_id',
'team_id',
];

protected static function boot()
Expand All @@ -44,6 +46,9 @@ protected static function boot()

static::creating(function ($item) {
$item->ulid = self::generateUlid();
if (auth()->check()) {
$item->team_id = Filament::getTenant()?->id;
}
});
}

Expand All @@ -52,6 +57,11 @@ public function location(): BelongsTo
return $this->belongsTo(Location::class);
}

public function team(): BelongsTo
{
return $this->belongsTo(Team::class);
}

protected function casts(): array
{
return [
Expand Down
19 changes: 19 additions & 0 deletions app/Models/Location.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace App\Models;

use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Location extends Model
{
Expand All @@ -14,12 +16,24 @@ class Location extends Model
'description',
'parent_id',
'is_active',
'team_id',
];

protected $casts = [
'is_active' => 'boolean',
];

protected static function boot()
{
parent::boot();

static::creating(function ($item) {
if (auth()->check()) {
$item->team_id = Filament::getTenant()?->id;
}
});
}

public function parent(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{
return $this->belongsTo(Location::class);
Expand All @@ -29,4 +43,9 @@ public function childrens(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(Location::class, 'parent_id');
}

public function team(): BelongsTo
{
return $this->belongsTo(Team::class);
}
}
30 changes: 29 additions & 1 deletion app/Models/Team.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

namespace App\Models;

use Filament\Models\Contracts\HasCurrentTenantLabel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Laravel\Jetstream\Events\TeamCreated;
use Laravel\Jetstream\Events\TeamDeleted;
use Laravel\Jetstream\Events\TeamUpdated;
use Laravel\Jetstream\Team as JetstreamTeam;

class Team extends JetstreamTeam
class Team extends JetstreamTeam implements HasCurrentTenantLabel
{
use HasFactory;

Expand Down Expand Up @@ -44,4 +45,31 @@ protected function casts(): array
'personal_team' => 'boolean',
];
}

protected static function boot()
{
parent::boot();

static::creating(function ($team) {
if (auth()->check()) {
$team->user_id = auth()->id();
$team->personal_team = false;
}
});
}

public function getCurrentTenantLabel(): string
{
return 'Current team';
}

public function locations(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(Location::class);
}

public function items(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(Item::class);
}
}
15 changes: 14 additions & 1 deletion app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasTenants;
use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Collection;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Jetstream\HasTeams;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable implements FilamentUser
class User extends Authenticatable implements FilamentUser, HasTenants //, MustVerifyEmail
{
use HasApiTokens;
use HasFactory;
Expand Down Expand Up @@ -71,4 +74,14 @@ public function canAccessPanel(Panel $panel): bool
{
return true;
}

public function getTenants(Panel $panel): Collection
{
return $this->allTeams();
}

public function canAccessTenant(Model $tenant): bool
{
return $this->allTeams()->count();
}
}
Loading

0 comments on commit e467f5e

Please sign in to comment.