Passa al contenuto principale

Controller e API

I controller Laravel gestiscono la logica di business e forniscono le API per l'interazione con l'applicazione. Sono organizzati in moduli funzionali per una migliore manutenibilitร .

๐ŸŽฏ AssistantControllerโ€‹

Il controller principale per la gestione degli assistenti AI.

app/Http/Controllers/AssistantController.php
class AssistantController extends AssistantAgentController
{
protected $nodeApiService;

public function __construct(NodeApiService $nodeApiService)
{
parent::__construct($nodeApiService);
}

public function index($module = 'assistants')
{
return parent::index($module);
}

public function create()
{
$user = auth()->user();

// Pulizia file temporanei
Session::forget('temp_files');
$this->cleanupTempFiles();

// Recupero prompt templates
$instructionPrompts = PromptTemplate::where('type', 'instruction')
->where(function($q) use ($user) {
if ($user->role === 'editor') {
$q->where('company_id', $user->company_id);
} else {
$q->whereNull('company_id');
}
})->orderBy('company_id')->orderBy('name', 'asc')->get();

$typePrompts = PromptTemplate::where('type', 'type')
->orderBy('name', 'asc')->get();

$personalityPrompts = PromptTemplate::where('type', 'personality')
->orderBy('name', 'asc')->get();

$companies = Company::all();

return view('modules.assistants.create', compact(
'companies', 'instructionPrompts', 'typePrompts', 'personalityPrompts'
));
}
}

Metodi Principali AssistantControllerโ€‹

store() - Creazione Assistenteโ€‹

app/Http/Controllers/AssistantController.php
public function store(Request $request)
{
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'type_prompt_id' => 'required|exists:prompt_templates,id',
'personality_type_id' => 'nullable|exists:prompt_templates,id',
'instructions' => 'nullable|string',
'company_id' => 'nullable|string',
]);

$user = auth()->user();
$tempFiles = Session::get('temp_files', []);

try {
// Costruzione delle istruzioni
$typePrompt = PromptTemplate::findOrFail($validatedData['type_prompt_id']);
$personalityPrompt = isset($validatedData['personality_type_id'])
? PromptTemplate::findOrFail($validatedData['personality_type_id'])
: '';
$userInstructions = $validatedData['instructions'] ?? '';

$instructions = trim($typePrompt['prompt'] . "\n\n" .
(isset($personalityPrompt['prompt']) ? $personalityPrompt['prompt'] : '') .
"\n\n" . $userInstructions);

// Creazione assistente
$assistant = Assistant::create([
'company_id' => $user->role === 'editor' ? $user->company_id : $validatedData['company_id'],
'name' => $validatedData['name'],
'model' => 'gpt-4o',
'instructions' => $instructions,
'assistant_uuid' => Str::uuid(),
'vector_store_uuid' => null,
'embedding_options' => json_encode($this->defaultEmbeddingOptions)
]);

// Creazione vector store
$vectorStoreUuid = NodeApiService::createCollection($assistant);
$assistant->vector_store_uuid = $vectorStoreUuid;
$assistant->save();

// Processamento file temporanei
foreach ($tempFiles as $file) {
$this->processTempFile($file, $assistant, $vectorStoreUuid, $user);
}

Session::forget('temp_files');
return redirect('/assistants/edit/' . $assistant->id)
->with('success', 'Assistente creato con successo.');

} catch (\Exception $e) {
Log::error('Errore nella creazione dell\'assistente: ' . $e->getMessage());
return back()->with('error', 'Si รจ verificato un errore durante la creazione dell\'assistente.');
}
}

update() - Aggiornamento Assistenteโ€‹

app/Http/Controllers/AssistantController.php
public function update(Request $request, string $id)
{
try {
$user = auth()->user();

if ($user->role === 'editor') {
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'domains' => 'nullable|string',
]);
} else {
$validatedData = $request->validate([
'company_id' => 'required|int',
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'domains' => 'nullable|string',
]);
}

// Recupero e concatenazione prompt
$prompts = AssistantPrompt::where('assistant_id', $id)
->where('enabled', true)
->orderBy('order')
->pluck('content')
->toArray();
$combinedPrompts = implode(" \n", $prompts);
$validatedData['instructions'] = $combinedPrompts;

$assistant = Assistant::findOrFail($id);

if ($user->cannot('update', $assistant)) {
abort(403);
}

$assistant->update($validatedData);

$redirectUrl = '/assistants/edit/' . $assistant->id;
if ($request->has('tab')) {
$redirectUrl .= '?tab=' . $request->get('tab');
}

return redirect($redirectUrl)
->with('success', 'Assistente aggiornato correttamente.');

} catch (\Exception $e) {
Log::error('Errore nell\'aggiornamento dell\'assistente: ' . $e->getMessage());
return back()->with('error', 'Si รจ verificato un errore durante l\'aggiornamento dell\'assistente.');
}
}

๐Ÿค– AgentControllerโ€‹

Gestisce gli agenti AI per e-commerce e WooCommerce.

app/Http/Controllers/AgentController.php
class AgentController extends AssistantAgentController
{
public function __construct(NodeApiService $nodeApiService)
{
parent::__construct($nodeApiService);
}

public function index($module = 'agents')
{
return parent::index($module);
}

public function create()
{
$user = auth()->user();
$companies = Company::all();

if ($user->role === 'editor') {
$company = Company::findOrFail($user->company_id);
} else {
$company = null;
}

return view('modules.agents.create', compact('companies'));
}

public function store(Request $request)
{
$user = auth()->user();

if ($user->role === 'editor') {
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'company_name' => 'nullable|string|max:255',
'company_description' => 'nullable|string',
'domains' => 'nullable|string',
'language' => 'required|string|in:italian,english,french,german,spanish,portuguese,russian',
'enable_extra_instructions' => 'nullable|boolean',
'extra_instructions' => 'nullable|string',
]);
} else {
$validatedData = $request->validate([
'company_id' => 'required|integer|exists:companies,id',
'name' => 'required|string|max:255',
'company_name' => 'nullable|string|max:255',
'company_description' => 'nullable|string',
'domains' => 'nullable|string',
'language' => 'required|string|in:italian,english,french,german,spanish,portuguese,russian',
'enable_extra_instructions' => 'nullable|boolean',
'extra_instructions' => 'nullable|string',
]);
}

// Creazione agente
$agent = Agent::create([
'company_id' => $user->role === 'editor' ? $user->company_id : $validatedData['company_id'],
'name' => $validatedData['name'],
'company_name' => $validatedData['company_name'] ?? '',
'company_description' => $validatedData['company_description'] ?? '',
'domains' => $validatedData['domains'] ?? '',
'language' => $validatedData['language'],
'extra_instructions' => $validatedData['extra_instructions'] ?? '',
'agent_uuid' => Str::uuid(),
]);

return redirect('/agents/edit/' . $agent->id)
->with('success', 'Agente creato con successo.');
}
}

๐Ÿ’ฌ ConversationControllerโ€‹

Gestisce le conversazioni e i thread di chat.

app/Http/Controllers/ConversationController.php
class ConversationController extends Controller
{
public function list($conversationId)
{
$messages = Message::where('conversation_id', $conversationId)
->orderBy('created_at', 'asc')
->orderBy('sender', 'asc')
->get();

$htmlContent = '';
foreach ($messages as $message) {
$sanitizedMessage = Purifier::clean($message->message);
$sanitizedMessage = $this->addClassToAnchorTags($sanitizedMessage, 'text-blue-700');

$htmlContent .= view('components.chat-bubble', [
'type' => $message->sender,
'message' => $sanitizedMessage,
'time' => $message->created_at->format('j M Y') . ' alle ' . $message->created_at->format('H:i'),
'cost' => number_format($message->cost, 6, ',')
])->render();
}

return response()->json($htmlContent);
}

public function store(Request $request)
{
$uuid = $request->assistant_or_agent_uuid;
$type = $request->type;

if ($type === 'assistant') {
$assistant = Assistant::where('assistant_uuid', $uuid)->first();
} else if ($type === 'agent') {
$uuid = str_replace('agent_', '', $uuid);
$assistant = Agent::where('agent_uuid', $uuid)->first();
} else {
return response()->json(['error' => 'Invalid type.'], 400);
}

if (!$assistant) {
return response()->json(['error' => 'Assistant not found.'], 404);
}

$attributes = [
'conversation_uuid' => $request->conversation_uuid,
'started_at' => Carbon::now(),
'ended_at' => Carbon::now(),
'tokens_used' => 0,
'domain' => $request->domain,
'location' => json_encode($request->location)
];

if ($request->type === 'assistant') {
$attributes['assistant_id'] = $assistant->id;
$attributes['agent_id'] = null;
} else {
$attributes['agent_id'] = $assistant->id;
$attributes['assistant_id'] = null;
}

$conversation = Conversation::create($attributes);

// Notifica se abilitata
$notifyNewConversation = data_get($assistant->notification, 'notify_new_conversation', false);
if ($notifyNewConversation) {
$assistant->company->notify(new NewConversationNotification($assistant, $conversation));
}

return response()->json($conversation, 201);
}
}

๐Ÿ“ MessageControllerโ€‹

Gestisce i singoli messaggi all'interno delle conversazioni.

app/Http/Controllers/MessageController.php
class MessageController extends Controller
{
public function store(Request $request)
{
$conversation = Conversation::where('conversation_uuid', $request->conversation_uuid)->first();
if (!$conversation) {
return response()->json(['error' => 'Conversation not found.'], 404);
}

$model = ModelAI::where('name', $request->model)->first();
if (!$model) {
return response()->json(['error' => 'Model not found.'], 404);
}

// Calcolo costi
$input_cost_per_token = $model->input_cost_per_tokens / $model->tokens;
$output_cost_per_token = $model->output_cost_per_tokens / $model->tokens;

$cost = 0;
$tokens_used = 0;
$input_tokens = 0;
$output_tokens = 0;
$cache_read = 0;

if ($request->has('tokens') && $request->tokens) {
$tokens = $request->tokens;
if (is_array($tokens)) {
$input_tokens = ($tokens['input_tokens'] - $tokens['cache_read']) ?? 0;
$output_tokens = $tokens['output_tokens'] ?? 0;
$cache_read = $tokens['cache_read'] ?? 0;
$tokens_used = $tokens['total_tokens'] ?? 0;
}

$cost += ($input_cost_per_token * $input_tokens) * $model->commission_rate;
$cost += ($output_cost_per_token * $output_tokens) * $model->commission_rate;
$cost += ($input_cost_per_token * $cache_read) * $model->commission_rate;
}

DB::beginTransaction();
try {
$message = Message::where('message_uuid', $request->message_uuid)->first();
if ($message) {
return response()->json(['error' => 'Message already exists.'], 400);
}

$message = Message::create([
'conversation_id' => $conversation->id,
'message_uuid' => $request->message_uuid,
'sender' => $request->sender,
'message' => $request->message,
'tokens_used' => $tokens_used,
'model' => $request->model,
'cost' => $cost,
]);

// Aggiornamento conversazione
$conversation->update([
'ended_at' => now(),
'tokens_used' => $conversation->tokens_used + $tokens_used,
'input_tokens_used' => $conversation->input_tokens_used + $input_tokens,
'output_tokens_used' => $conversation->output_tokens_used + $output_tokens,
'input_cost' => $conversation->input_cost + ($input_cost_per_token * $input_tokens) * $model->commission_rate,
'output_cost' => $conversation->output_cost + ($output_cost_per_token * $output_tokens) * $model->commission_rate,
]);

DB::commit();
return response()->json($message, 201);
} catch (\Exception $e) {
DB::rollBack();
Log::error('Error creating message', ['error' => $e->getMessage()]);
return response()->json(['error' => $e->getMessage()], 500);
}
}
}

๐Ÿข CompanyControllerโ€‹

Gestisce le informazioni delle aziende e i loro abbonamenti.

app/Http/Controllers/CompanyController.php
class CompanyController extends Controller
{
public function index(Request $request)
{
$companies = Company::with(['assistants', 'agents'])->get();

$startOfMonth = now()->startOfMonth();
$endOfMonth = now()->endOfMonth();

foreach ($companies as $company) {
$company['totalMessagesConsumed'] = 0;
$company->messageLimit = $company->subscriptionPlan()->max_messages ?? 0;

foreach ($company->assistants as $assistant) {
$conversationIds = $assistant->conversations()->pluck('id');
$totalMessages = Message::whereIn('conversation_id', $conversationIds)
->whereBetween('created_at', [$startOfMonth, $endOfMonth])
->count();
$company['totalMessagesConsumed'] += $totalMessages;
}
}

return view('modules.companies.index', compact('companies'));
}
}

๐Ÿ”‘ JWTControllerโ€‹

Gestisce l'autenticazione JWT per le API.

app/Http/Controllers/JWTController.php
class JWTController extends Controller
{
public static function refreshToken(Request $request)
{
try {
$validator = Validator::make($request->all(), [
'refresh_token' => 'required|string'
]);

if ($validator->fails()) {
return response()->json([
'error' => 'Validation failed',
'details' => $validator->errors()
], 400);
}

$refreshToken = $request->input('refresh_token');
$tokens = JWTService::refreshJwtTokens($refreshToken);

return response()->json([
'success' => true,
'data' => $tokens
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'error' => $e->getMessage()
], 401);
}
}
}

๐Ÿ“Š DashboardControllerโ€‹

Fornisce le statistiche e i dati per la dashboard.

app/Http/Controllers/DashboardController.php
class DashboardController extends Controller
{
public function index(Request $request)
{
$user = auth()->user();

if ($user->role != 'admin') {
if ($user->company) {
if (is_null($user->company->subscriptionPlan())) {
$freePlan = SubscriptionPlan::where('name', 'FREE')->first();
if (!$freePlan) {
$freePlan = SubscriptionPlan::create([
'name' => 'FREE',
'max_assistants' => 1,
'max_messages' => 500,
'max_file_uploads' => 1,
'storage_limit_mb' => 10,
'is_default' => 1,
]);
}
}
}
}

return view('dashboard');
}
}

๐Ÿ“ FileControllerโ€‹

Gestisce l'upload e la gestione dei file per assistenti e agenti.

app/Http/Controllers/FileController.php
class FileController extends Controller
{
private int $maxFileSizeKb;

public function __construct()
{
$this->maxFileSizeKb = config('app.max_file_size_kb', 256000); // 250MB
}

public function upload(Request $request)
{
$user = auth()->user();

$validationRules = [
'is_agent' => 'required|boolean',
'assistant_id' => 'required_if:is_agent,false|exists:assistants,id',
'agent_id' => 'required_if:is_agent,true|exists:agents,id',
'file' => 'nullable|array',
'file.*' => 'file|mimes:pdf,txt,docx,csv,xml,xlsx,json,docx',
'url' => 'nullable|url',
'api_url' => 'nullable|url',
'api_request_type' => 'nullable|in:GET,POST',
'jwt_token' => 'nullable|string',
'api_request_body' => 'nullable|string',
'refresh_interval_days' => 'nullable|integer',
];

$request->validate($validationRules);

// Processamento file
if ($request->hasFile('file')) {
$files = $request->file('file');
if (!is_array($files)) {
$files = [$files];
}

foreach ($files as $file) {
$fileSize = $file->getSize();
if ($fileSize > $this->maxFileSizeKb * 1024) {
return response()->json([
'success' => false,
'message' => 'Il file รจ troppo grande. Limite: ' . $this->maxFileSizeKb . ' KB'
]);
}
}
}

// Creazione record file
$file = File::create([
'company_id' => $user->company_id,
'assistant_id' => $request->is_agent ? null : $request->assistant_id,
'agent_id' => $request->is_agent ? $request->agent_id : null,
'file_name' => $request->file('file')[0]->getClientOriginalName() ?? 'url_file',
'file_path' => 'temp_path',
'file_size' => $fileSize ?? 0,
'file_type' => $request->file('file')[0]->getMimeType() ?? 'url',
'file_uuid' => Str::uuid(),
]);

return response()->json([
'success' => true,
'message' => 'File caricato con successo',
'file' => $file
]);
}
}

๐Ÿ”” NotificationControllerโ€‹

Gestisce le notifiche del sistema.

app/Http/Controllers/NotificationController.php
class NotificationController extends Controller
{
public function index(Request $request)
{
$user = auth()->user();

$query = Notification::where('company_id', $user->company_id)
->orderBy('created_at', 'desc');

if ($request->has('status')) {
$query->where('status', $request->status);
}

if ($request->has('type')) {
$query->where('type', $request->type);
}

$notifications = $query->paginate(20);

return response()->json([
'success' => true,
'notifications' => $notifications
]);
}

public function markAsRead(Request $request, $id)
{
$user = auth()->user();

$notification = Notification::where('id', $id)
->where('company_id', $user->company_id)
->first();

if (!$notification) {
return response()->json([
'success' => false,
'message' => 'Notification not found.'
], 404);
}

$notification->update(['status' => 'read']);

return response()->json([
'success' => true,
'message' => 'Notification marked as read.'
]);
}

public function markAllAsRead(Request $request)
{
$user = auth()->user();

Notification::where('company_id', $user->company_id)
->where('status', 'unread')
->update(['status' => 'read']);

return response()->json([
'success' => true,
'message' => 'All notifications marked as read.'
]);
}
}

๐Ÿ‘ฅ UserControllerโ€‹

Gestisce gli utenti del sistema.

app/Http/Controllers/UserController.php
class UserController extends Controller
{
public function index(Request $request)
{
$users = User::query()
->leftJoin('companies', 'users.company_id', '=', 'companies.id')
->select('users.*', 'companies.name as company_name')
->get();

return view('modules.users.index', compact('users'));
}

public function create()
{
$companies = Company::all();
return view('modules.users.create', compact('companies'));
}

public function store(Request $request)
{
$validatedData = $request->validate([
'company_id' => 'nullable',
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'role' => 'required|string|in:admin,editor',
'password' => ['required', Password::defaults(), 'confirmed'],
]);

$user = User::create([
'company_id' => $validatedData['company_id'] ?? null,
'name' => $validatedData['name'],
'email' => $validatedData['email'],
'role' => $validatedData['role'],
'password' => Hash::make($validatedData['password']),
]);

return redirect('/users/edit/' . $user->id)
->with('success', 'Utente creato con successo.');
}
}

๐Ÿ”‘ ApiKeyControllerโ€‹

Gestisce le chiavi API per l'integrazione.

app/Http/Controllers/ApiKeyController.php
class ApiKeyController extends Controller
{
public function index(Request $request)
{
$user = auth()->user();
$keysQuery = ApiKey::query();

if ($user->role === 'editor') {
$keysQuery->where('company_id', $user->company_id);
}

$keys = $keysQuery->get();
return view('modules.api_keys.index', compact('keys'));
}

public function store(Request $request)
{
$user = auth()->user();
$request->merge(['active' => $request->has('active')]);

if ($user->role === 'admin') {
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'note' => 'nullable|string',
'allowed_host' => 'nullable|string',
'active' => 'nullable|boolean',
'company_id' => 'required|integer|exists:companies,id'
]);
} else {
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'note' => 'nullable|string',
'active' => 'nullable|boolean',
'allowed_host' => 'nullable|string',
]);
$validatedData['company_id'] = $user->company_id;
}

$randomKey = Str::random(32);
$encryptedKey = hash_hmac('sha256', $randomKey, date('hi'));
$validatedData['key'] = $encryptedKey;

$apikey = ApiKey::create($validatedData);

return redirect('/api-keys/edit/' . $apikey->id)
->with('success', 'Chiave API creata con successo.')
->with('api_key', $randomKey);
}
}

๐Ÿ’ณ SubscriptionPlanControllerโ€‹

Gestisce i piani di abbonamento.

app/Http/Controllers/SubscriptionPlanController.php
class SubscriptionPlanController extends Controller
{
protected StripeApiService $stripeApiService;

public function __construct(StripeApiService $stripeApiService)
{
$this->stripeApiService = $stripeApiService;
}

public function index(Request $request)
{
$subscriptionPlans = SubscriptionPlan::orderBy('sort_order', 'asc')
->orderBy('created_at', 'asc')
->get();

return view('modules.subscription_plans.index', compact('subscriptionPlans'));
}

public function store(Request $request)
{
$rules = [
'name' => 'required|string|max:255',
'short_description' => 'nullable|string|max:500',
'max_assistants' => 'required|integer|min:0',
'max_products' => 'required|integer|min:0',
'max_messages' => 'required|integer|min:0',
'max_file_uploads' => 'required|integer|min:0',
'storage_limit_mb' => 'required|integer|min:0',
'is_default' => 'boolean',
'monthly_price' => 'nullable|numeric|min:0',
'yearly_price' => 'nullable|numeric|min:0',
'is_custom' => 'boolean',
'features' => 'nullable|string',
'sort_order' => 'nullable|integer|min:0',
];

$validated = $request->validate($rules);

if (empty($validated['monthly_price']) && empty($validated['yearly_price']) && $validated['name'] !== 'FREE') {
return back()->withErrors(['monthly_price' => 'Almeno uno tra prezzo mensile e annuale deve essere specificato.'])->withInput();
}

if (!isset($validated['sort_order'])) {
$maxSort = SubscriptionPlan::max('sort_order') ?? 0;
$validated['sort_order'] = $maxSort + 1;
}

SubscriptionPlan::create($validated);
$this->clearSparkCache();

return redirect()->route('subscription_plans')->with('success', 'Piano creato con successo');
}
}

๐Ÿ‘ค ProfileControllerโ€‹

Gestisce il profilo utente e azienda.

app/Http/Controllers/ProfileController.php
class ProfileController extends Controller
{
public function edit(Request $request): View
{
return view('profile.edit', [
'user' => $request->user(),
'company' => $request->user()->company,
]);
}

public function update(ProfileUpdateRequest $request): RedirectResponse
{
$request->user()->fill($request->validated());

if ($request->user()->isDirty('email')) {
$request->user()->email_verified_at = null;
}

$request->user()->save();

return Redirect::route('profile.edit')->with('status', 'profile-updated');
}

public function updateCompany(Request $request)
{
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'address' => 'nullable|string|max:255',
'city' => 'nullable|string|max:100',
'province' => 'nullable|string|max:100',
'zipcode' => 'nullable|string|max:20',
'website' => 'nullable|string|max:255',
'vatcode' => 'nullable|string|max:50',
'phone' => 'nullable|string|max:20',
'email' => 'nullable|email|max:255',
'note' => 'nullable|string',
]);

$company = auth()->user()->company;
$company->update($validatedData);

return redirect('/profile')->with('success', 'Azienda modificata con successo');
}
}

๐ŸŒ API Routesโ€‹

Route per Assistentiโ€‹

routes/api.php
Route::controller(ConversationController::class)->group(function () {
Route::post('conversations', 'store');
Route::delete('conversations/{id}', 'destroy');
Route::get('conversations/{id}', 'show');
});

Route::controller(MessageController::class)->group(function () {
Route::post('messages', 'store');
Route::delete('messages/{id}', 'destroy');
Route::get('messages/{conversationId}', 'index');
});

Route::controller(AssistantController::class)->group(function () {
Route::get('/chat/js/{uuid}', 'jsChatbot');
Route::get('assistant/script/{uuid}', 'loadChatWidget');
Route::get('assistant/list/{key}', 'listAssistants');
Route::get('loadChat/{uuid}', 'loadChatWidget');
});

Route::controller(JWTController::class)->group(function () {
Route::post('jwt/refresh', 'refreshToken');
});

Route Webโ€‹

routes/web.php
Route::get('/', function () {
if (Auth::check()) {
return redirect()->route('dashboard');
}
return view('auth.login');
});

Route::match(['get', 'post'], '/dashboard', [DashboardController::class, 'index'])
->middleware(['auth', 'verified'])
->name('dashboard');

Route::get('/refresh-cache', [CacheController::class, 'refreshCache']);

๐Ÿ”’ Middleware e Autorizzazioniโ€‹

Policy per Assistentiโ€‹

app/Policies/AssistantPolicy.php
class AssistantPolicy
{
public function view(User $user, Assistant $assistant)
{
return $user->role === 'admin' ||
($user->role === 'editor' && $user->company_id === $assistant->company_id);
}

public function update(User $user, Assistant $assistant)
{
return $user->role === 'admin' ||
($user->role === 'editor' && $user->company_id === $assistant->company_id);
}

public function delete(User $user, Assistant $assistant)
{
return $user->role === 'admin' ||
($user->role === 'editor' && $user->company_id === $assistant->company_id);
}
}

Middleware Esistentiโ€‹

app/Http/Middleware/CheckAssistantLimit.php
class CheckAssistantLimit
{
public function handle($request, Closure $next)
{
$user = auth()->user();
$company = $user->company;

$subscriptionService = new SubscriptionService($company->id);

if (!$subscriptionService->canCreateAssistant()) {
return response()->json([
'error' => 'Assistant limit reached for your subscription plan'
], 403);
}

return $next($request);
}
}

I controller forniscono un'interfaccia pulita e ben strutturata per l'interazione con l'applicazione, gestendo l'autenticazione, l'autorizzazione e la logica di business in modo efficiente.