Last active
April 14, 2025 22:07
-
-
Save iurygdeoliveira/8c44cc5fef284d8cd37c1c6adcd83308 to your computer and use it in GitHub Desktop.
Divida técnica no filament 3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types = 1); | |
namespace App\Providers\Filament; | |
use Filament\Enums\ThemeMode; | |
use Filament\Forms\Components\Field; | |
use Filament\Http\Middleware\Authenticate; | |
use Filament\Http\Middleware\AuthenticateSession; | |
use Filament\Http\Middleware\DisableBladeIconComponents; | |
use Filament\Http\Middleware\DispatchServingFilamentEvent; | |
use Filament\Pages\Dashboard; | |
use Filament\Panel; | |
use Filament\PanelProvider; | |
use Filament\Tables\Columns\Column; | |
use Filament\Widgets; | |
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; | |
use Illuminate\Cookie\Middleware\EncryptCookies; | |
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken; | |
use Illuminate\Routing\Middleware\SubstituteBindings; | |
use Illuminate\Session\Middleware\StartSession; | |
use Illuminate\View\Middleware\ShareErrorsFromSession; | |
class AdminPanelProvider extends PanelProvider | |
{ | |
public function panel(Panel $panel): Panel | |
{ | |
return $panel | |
->bootUsing(function (): void { | |
Field::configureUsing(function (Field $field): void { | |
$field->translateLabel(); | |
}); | |
Column::configureUsing(function (Column $column): void { | |
$column->translateLabel(); | |
}); | |
}) | |
->darkMode(false) | |
->defaultThemeMode(ThemeMode::Light) | |
->default() | |
->id('admin') | |
->path('admin') | |
->login() | |
->registration() | |
->passwordReset() | |
->emailVerification() | |
->colors([ | |
'primary' => '#076fd1', | |
'secondary' => '#6b7a91', | |
'danger' => '#d5393a', | |
'warning' => '#f76707', | |
'success' => '#2eb347', | |
'info' => '#4398e0', | |
'light' => '#f7f8fc', | |
]) | |
->sidebarWidth('15rem') | |
->theme(asset('css/filament/admin/theme.css')) | |
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') | |
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages') | |
->pages([ | |
Dashboard::class, | |
]) | |
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets') | |
->widgets([ | |
Widgets\AccountWidget::class, | |
Widgets\FilamentInfoWidget::class, | |
]) | |
->middleware([ | |
EncryptCookies::class, | |
AddQueuedCookiesToResponse::class, | |
StartSession::class, | |
AuthenticateSession::class, | |
ShareErrorsFromSession::class, | |
VerifyCsrfToken::class, | |
SubstituteBindings::class, | |
DisableBladeIconComponents::class, | |
DispatchServingFilamentEvent::class, | |
]) | |
->authMiddleware([ | |
Authenticate::class, | |
]); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types = 1); | |
namespace App\Providers; | |
use App\Models\Scopes\TenantScope; | |
use App\Models\User; | |
use Carbon\CarbonImmutable; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Support\Facades\Auth; | |
use Illuminate\Support\Facades\Date; | |
use Illuminate\Support\Facades\DB; | |
use Illuminate\Support\ServiceProvider; | |
use Laravel\Telescope\TelescopeServiceProvider; | |
class AppServiceProvider extends ServiceProvider | |
{ | |
/** | |
* Register any application services. | |
*/ | |
#[\Override] | |
public function register(): void | |
{ | |
if ($this->app->environment('local')) { | |
$this->app->register(TelescopeServiceProvider::class); | |
} | |
} | |
/** | |
* Bootstrap any application services. | |
*/ | |
public function boot(): void | |
{ | |
$this->configModels(); | |
$this->configCommands(); | |
// $this->configUrls(); | |
$this->configDate(); | |
// app()->booted(function (): void { | |
// if (Auth::check()) { | |
// // Tenant::addGlobalScope(new TenantScope()); | |
// User::addGlobalScope(new TenantScope()); | |
// } | |
// }); | |
} | |
private function configModels(): void | |
{ | |
// Certificar de que todas as propriedades sendo chamadas existam no modelo | |
Model::shouldBeStrict(); | |
} | |
// Configura os comandos do banco de dados para proibir a execução de instruções destrutivas | |
// quando a aplicação está em execução em um ambiente de produção. | |
private function configCommands(): void | |
{ | |
DB::prohibitDestructiveCommands( | |
app()->isProduction() | |
); | |
} | |
private function configDate(): void | |
{ | |
Date::use(CarbonImmutable::class); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types = 1); | |
namespace App\Models; | |
use Illuminate\Database\Eloquent\Factories\HasFactory; | |
use Illuminate\Database\Eloquent\Model; | |
use OwenIt\Auditing\Contracts\Auditable; | |
class BaseModel extends Model implements Auditable | |
{ | |
use HasFactory; | |
use \OwenIt\Auditing\Auditable; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
status 200 OK | |
full_url http://localhost/admin/users | |
action_name filament.admin.resources.users.index | |
controller_action App\Filament\Resources\UserResource\Pages\ListUsers | |
uri GET admin/users | |
controller App\Filament\Resources\UserResource\Pages\ListUsers@render | |
prefix admin/users | |
file vendor/filament/filament/src/Pages/BasePage.php:51-59 | |
middleware | |
panel:admin, Illuminate\Cookie\Middleware\EncryptCookies, Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse, Illuminate\Session\Middleware\StartSession, Filament\Http\Middleware\AuthenticateSession, Illuminate\View\Middleware\ShareErrorsFromSession, Illuminate\Foundation\Http\Middleware\VerifyCsrfToken, Illuminate\Routing\Middleware\SubstituteBindings, Filament\Http\Middleware\DisableBladeIconComponents, Filament\Http\Middleware\DispatchServingFilamentEvent, Filament\Http\Middleware\Authenticate, verified:filament.admin.auth.email-verification.prompt | |
duration 691ms | |
peak_memory 16MB | |
response text/html; charset=UTF-8 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types = 1); | |
return [ | |
App\Providers\AppServiceProvider::class, | |
App\Providers\Filament\AdminPanelProvider::class, | |
App\Providers\TelescopeServiceProvider::class, | |
]; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types = 1); | |
namespace App\Models; | |
use Illuminate\Database\Eloquent\Relations\HasMany; | |
class Tenant extends BaseModel | |
{ | |
protected $fillable = [ | |
'name', | |
]; | |
/** | |
* Obtém todos os usuários pertencentes a este inquilino (tenant). | |
* Este método estabelece um relacionamento um-para-muitos onde: | |
* - Um inquilino pode ter múltiplos usuários | |
* - Cada usuário pertence a um inquilino | |
* - A chave estrangeira 'tenant_id' na tabela users referencia este inquilino | |
*/ | |
public function users(): HasMany | |
{ | |
return $this->hasMany(User::class); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// DIVÍDA TÉCNICA | |
// O app entra em loop quando tenta acessar um usuario autenticado | |
// Aparentemente é um problema com o middlewares no filament 3 | |
// A filtragem por tenant funciona | |
<?php | |
declare(strict_types = 1); | |
namespace App\Models\Scopes; | |
use Illuminate\Database\Eloquent\Builder; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Database\Eloquent\Scope; | |
use Illuminate\Support\Facades\Auth; | |
use Illuminate\Support\Facades\Log; | |
class TenantScope implements Scope | |
{ | |
/** | |
* Apply the scope to a given Eloquent query builder. | |
*/ | |
public function apply(Builder $builder, Model $model): void | |
{ | |
Log::info(Auth::user()); // A aplicação entre em loop | |
$builder->where('tenant_id', 1); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types = 1); | |
namespace App\Models; | |
// use Illuminate\Contracts\Auth\MustVerifyEmail; | |
use App\Models\Scopes\TenantScope; | |
use Carbon\Carbon; | |
use Illuminate\Database\Eloquent\Factories\HasFactory; | |
use Illuminate\Database\Eloquent\Relations\BelongsTo; | |
use Illuminate\Foundation\Auth\User as Authenticatable; | |
use Illuminate\Notifications\Notifiable; | |
use OwenIt\Auditing\Contracts\Auditable; | |
class User extends Authenticatable implements Auditable | |
{ | |
/** @use HasFactory<\Database\Factories\UserFactory> */ | |
use HasFactory; | |
use Notifiable; | |
use \OwenIt\Auditing\Auditable; | |
protected $fillable = [ | |
'name', | |
'email', | |
'password', | |
'tenant_id', | |
]; | |
protected $hidden = [ | |
'password', | |
'remember_token', | |
]; | |
protected function casts(): array | |
{ | |
return [ | |
'email_verified_at' => 'datetime:d/m/Y H:i', | |
'password' => 'hashed', | |
'suspended_until' => 'datetime:d/m/Y H:i', | |
'created_at' => 'datetime:d/m/Y H:i', | |
'updated_at' => 'datetime:d/m/Y H:i', | |
'deleted_at' => 'datetime:d/m/Y H:i', | |
]; | |
} | |
public function setCreatedAtAttribute(\DateTimeInterface | \Carbon\WeekDay | \Carbon\Month | string | int | float | null $value): void | |
{ | |
$this->attributes['created_at'] = Carbon::parse($value)->toDateTimeString(); | |
} | |
/** | |
* Define o relacionamento com o inquilino (tenant) ao qual este usuário pertence. | |
* Este método estabelece um relacionamento muitos-para-um onde: | |
* - Muitos usuários podem pertencer a um único tenant | |
* - O campo tenant_id na tabela users é a chave estrangeira | |
* - Cada usuário só pode pertencer a um tenant | |
*/ | |
public function tenant(): BelongsTo | |
{ | |
return $this->belongsTo(Tenant::class); | |
} | |
#[\Override] | |
protected static function booted() | |
{ | |
static::addGlobalScope(new TenantScope()); | |
} | |
/** | |
* Verifica se o usuário está suspenso. | |
* Um usuário é considerado suspenso se a data de suspensão (suspended_until) não for nula | |
* e a data atual for menor que a data de suspensão. | |
*/ | |
public function suspended(): bool | |
{ | |
return ! is_null($this->suspended_until) && Carbon::now()->lessThan($this->suspended_until); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types = 1); | |
namespace App\Filament\Resources; | |
use App\Filament\Resources\UserResource\Pages; | |
use App\Models\User; | |
use Filament\Forms\Components\TextInput; | |
use Filament\Forms\Form; | |
use Filament\Resources\Resource; | |
use Filament\Tables\Actions\BulkActionGroup; | |
use Filament\Tables\Actions\DeleteBulkAction; | |
use Filament\Tables\Actions\EditAction; | |
use Filament\Tables\Columns\TextColumn; | |
use Filament\Tables\Table; | |
/** | |
* Recurso do Filament para gerenciamento de usuários. | |
* Esta classe permite listar, criar, editar e excluir usuários através da interface administrativa do Filament. | |
* Fornece formulários, tabelas e relacionamentos para o modelo User. | |
*/ | |
class UserResource extends Resource | |
{ | |
/** | |
* Define o modelo associado a este recurso. | |
* Neste caso, o recurso gerencia o modelo User. | |
*/ | |
protected static ?string $model = User::class; | |
/** | |
* Define o ícone de navegação para este recurso no menu lateral. | |
* Utiliza o ícone 'rectangle-stack' da biblioteca Heroicons. | |
*/ | |
protected static ?string $navigationIcon = 'heroicon-s-users'; | |
#[\Override] | |
public static function getModelLabel(): string | |
{ | |
return __('User'); | |
} | |
/** | |
* Define o formulário para criar e editar registros de usuários. | |
* Este método configura os campos do formulário, suas validações e comportamentos. | |
* Inclui campos para nome, email e senha, com regras apropriadas para cada um. | |
*/ | |
#[\Override] | |
public static function form(Form $form): Form | |
{ | |
return $form | |
->schema([ | |
TextInput::make('name') | |
->required(), | |
TextInput::make('email') | |
->email() | |
->required() | |
->unique(ignoreRecord: true), | |
TextInput::make('password') | |
->password() | |
->required(fn (string $operation): bool => $operation === 'create') | |
->dehydrated(fn (?string $state) => filled($state)) | |
->confirmed(), | |
TextInput::make('password_confirmation') | |
->password() | |
->requiredWith('password') | |
->dehydrated(false), | |
]); | |
} | |
/** | |
* Define a tabela para exibição e gerenciamento de usuários. | |
* Este método configura a tabela com paginação, colunas, filtros, ações individuais e em massa. | |
* Inclui colunas para nome, email, status de verificação e timestamps, com opções de busca e ordenação. | |
*/ | |
#[\Override] | |
public static function table(Table $table): Table | |
{ | |
return $table | |
->extremePaginationLinks() | |
->defaultPaginationPageOption(20) | |
->paginated([20, 40, 60, 80, 'all']) | |
->columns([ | |
TextColumn::make('name') | |
->searchable() | |
->sortable(), | |
TextColumn::make('email') | |
->searchable() | |
->sortable(), | |
TextColumn::make('verified') | |
->badge() | |
->formatStateUsing( | |
fn (string $state): string => $state !== '' && $state !== '0' ? 'Sim' : 'Não' | |
) | |
->color(fn (string $state): string => $state !== '' && $state !== '0' ? 'success' : 'danger') | |
->sortable(), | |
TextColumn::make('created_at') | |
->dateTime('d/m/Y H:i') | |
->searchable() | |
->sortable(), | |
TextColumn::make('updated_at') | |
->dateTime('d/m/Y H:i') | |
->searchable() | |
->sortable(), | |
]) | |
->defaultSort('name', 'asc') | |
->filters([ | |
// | |
]) | |
->actions([ | |
EditAction::make(), | |
]) | |
->bulkActions([ | |
BulkActionGroup::make([ | |
DeleteBulkAction::make(), | |
]), | |
]); | |
} | |
/** | |
* Define os relacionamentos disponíveis para o recurso de usuário. | |
* Este método configura quais relacionamentos serão exibidos na interface do Filament. | |
* Atualmente não há relacionamentos configurados, mas podem ser adicionados conforme necessário. | |
*/ | |
#[\Override] | |
public static function getRelations(): array | |
{ | |
return [ | |
// | |
]; | |
} | |
/** | |
* Define as páginas disponíveis para o recurso de usuário. | |
* Este método configura as rotas e páginas que serão usadas para listar, criar e editar usuários. | |
* Inclui páginas para listagem (index), criação (create) e edição (edit) de usuários, com suas respectivas rotas. | |
*/ | |
#[\Override] | |
public static function getPages(): array | |
{ | |
return [ | |
'index' => Pages\ListUsers::route('/'), | |
'create' => Pages\CreateUser::route('/create'), | |
'edit' => Pages\EditUser::route('/{record}/edit'), | |
]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment