mivita/app/Http/Controllers/BusinessControllerOptimized.php
2025-10-20 17:42:08 +02:00

575 lines
24 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\UserBusiness;
use App\Models\UserBusinessStructure;
use App\Services\BusinessPlan\BusinessUserRepository;
use App\Services\BusinessPlan\TreeCalcBotOptimized;
use App\Services\BusinessPlan\TreeHelperOptimized;
use App\Services\BusinessPlan\TreeHtmlRenderer;
use App\Services\HTMLHelper;
use App\Services\NextLevelBadgeHelper;
use App\User;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Request;
/**
* Optimierte Version des BusinessController
*
* Verbesserungen:
* - Nutzt TreeCalcBotOptimized für bessere Performance
* - Optimierte Datenbankabfragen durch Repository Pattern
* - Memory-effiziente Verarbeitung großer Datenmengen
* - Robuste Fehlerbehandlung mit Logging
* - Performance-Monitoring für Debugging
*/
class BusinessControllerOptimized extends Controller
{
private $filter_active = [1 => 'aktiv', 2 => 'nicht aktiv', 3 => 'alle'];
private $filter_next_level = [
0 => 'Alle Status',
1 => 'Qualifiziert (grün)',
2 => 'In Arbeit (gelb)',
3 => 'Kein Level (rot)'
];
private $month;
private $year;
public function __construct()
{
$this->middleware('admin');
}
/**
* Zeigt die Business-Übersicht (identisch zur Original-Version)
*/
public function show()
{
$this->setFilterVars();
$data = [
'filter_months' => HTMLHelper::getTransMonths(),
'filter_years' => HTMLHelper::getYearRange(),
'filter_active' => $this->filter_active,
'filter_levels' => $this->getFilterLevels(),
'filter_next_level' => $this->filter_next_level,
'optimized' => true, // Flag für View um zu zeigen, dass optimierte Version läuft
];
return view('admin.business_optimized.show', $data);
}
/**
* Zeigt die Business-Struktur mit optimierter TreeCalcBot-Version
*/
public function structure()
{
$startTime = microtime(true);
$startMemory = memory_get_usage();
try {
$this->setFilterVars();
$this->month = session('business_user_filter_month');
$this->year = session('business_user_filter_year');
Log::info("BusinessControllerOptimized: Building structure for {$this->month}/{$this->year}");
// Verwende optimierte TreeCalcBot-Version
$TreeCalcBot = new TreeCalcBotOptimized($this->month, $this->year, 'admin');
// Prüfe ob Live-Berechnung für Struktur erzwungen wird
$forceLiveCalculation = Request::get('force_live_calculation', false) ||
Request::get('force_live_structure', false) ||
Request::get('live', false);
if ($forceLiveCalculation) {
Log::info("BusinessControllerOptimized: Force live calculation requested");
$TreeCalcBot->initStructureAdmin(true, $forceLiveCalculation); // check=true, forceLiveCalculation=true
} else {
Log::info("BusinessControllerOptimized: Force live calculation not requested");
$TreeCalcBot->initStructureAdmin(); // Standard: verwende gespeicherte wenn verfügbar
}
$endTime = microtime(true);
$endMemory = memory_get_usage();
$executionTime = round(($endTime - $startTime) * 1000, 2);
$memoryUsed = $this->formatBytes($endMemory - $startMemory);
$calculationType = $forceLiveCalculation ? " (LIVE)" : " (CACHE)";
Log::info("BusinessControllerOptimized: Structure built in {$executionTime}ms, Memory: {$memoryUsed}{$calculationType}");
$data = [
'filter_months' => HTMLHelper::getTransMonths(),
'filter_years' => HTMLHelper::getYearRange(),
'TreeCalcBot' => $TreeCalcBot,
'performance' => [
'execution_time' => $executionTime,
'memory_used' => $memoryUsed,
'user_count' => $TreeCalcBot->getTotalUserCount(),
'parentless_count' => $TreeCalcBot->isParentless() ? count($TreeCalcBot->__get('parentless')) : 0,
'calculation_type' => $forceLiveCalculation ? 'Live' : 'Cache'
],
'optimized' => true,
'forceLiveCalculation' => $forceLiveCalculation,
];
return view('admin.business_optimized.structure', $data);
} catch (\Exception $e) {
Log::error("BusinessControllerOptimized: Error in structure: " . $e->getMessage());
return view('admin.business_optimized.error', [
'error' => $e->getMessage(),
'month' => $this->month,
'year' => $this->year
]);
}
}
/**
* Zeigt User-Details mit optimierter Performance
*/
public function userDetail($user_id)
{
$startTime = microtime(true);
try {
$user = User::with(['account', 'user_level', 'user_sponsor.account'])->findOrFail($user_id);
$this->setFilterVars();
$data = [];
$data['month'] = session('business_user_filter_month');
$data['year'] = session('business_user_filter_year');
Log::info("BusinessControllerOptimized: Building user detail for user {$user_id}");
$TreeCalcBot = new TreeCalcBotOptimized($data['month'], $data['year'], 'admin');
// Prüfe ob Live-Berechnung über URL-Parameter erzwungen wird
$forceLiveCalculation = Request::get('force_live_calculation', false) ||
Request::get('force_live', false) ||
Request::get('live', false);
if ($forceLiveCalculation) {
Log::info("BusinessControllerOptimized: Force live calculation requested for user {$user_id}");
}
$TreeCalcBot->initBusinesslUserDetail($user, $forceLiveCalculation);
if (!$TreeCalcBot->__get('business_user')) {
Log::warning("BusinessControllerOptimized: No business user found for {$user_id}");
abort(403, 'No business user found');
}
$endTime = microtime(true);
$executionTime = round(($endTime - $startTime) * 1000, 2);
$data['performance'] = [
'execution_time' => $executionTime,
'user_id' => $user_id,
'calculation_type' => $forceLiveCalculation ? 'Live' : 'Cache'
];
$data['forceLiveCalculation'] = $forceLiveCalculation;
$calculationType = $forceLiveCalculation ? " (LIVE)" : " (CACHE)";
Log::info("BusinessControllerOptimized: User detail built in {$executionTime}ms{$calculationType}");
return view('admin.business_optimized.user_detail', compact('TreeCalcBot', 'user', 'data'));
} catch (\Exception $e) {
Log::error("BusinessControllerOptimized: Error in userDetail for {$user_id}: " . $e->getMessage());
return view('admin.business_optimized.error', [
'error' => $e->getMessage(),
'user_id' => $user_id
]);
}
}
/**
* Store-Funktion (identisch zur Original-Version)
*/
public function userStore($user_id)
{
dd('function on: App\Console\Commands\BusinessStore');
}
/**
* Optimierte DataTable für Users mit besserer Performance
*/
public function userDatatable(): JsonResponse
{
try {
$this->month = Request::get('business_user_filter_month');
$this->year = Request::get('business_user_filter_year');
Log::info("BusinessControllerOptimized: Building datatable for {$this->month}/{$this->year}");
// Prüfe ob optimierte Repository-Daten verfügbar sind
if (TreeCalcBotOptimized::isFromStored($this->month, $this->year)) {
return $this->userStoredDatatableOptimized();
} else {
return $this->userCurrentlyDatatableOptimized();
}
} catch (\Exception $e) {
Log::error("BusinessControllerOptimized: Error in userDatatable: " . $e->getMessage());
return response()->json([
'error' => 'Datatable could not be loaded: ' . $e->getMessage()
], 500);
}
}
/**
* Optimierte Stored-Datatable mit besserer Query-Performance
*/
private function userStoredDatatableOptimized(): JsonResponse
{
$query = $this->initStoredSearchOptimized();
return \DataTables::eloquent($query)
->addColumn('id', function (UserBusiness $userBusiness) {
return TreeHelperOptimized::generateActionButtons($userBusiness->user_id);
})
->addColumn('m_account', function (UserBusiness $userBusiness) {
return e($userBusiness->m_account);
})
->addColumn('user_level', function (UserBusiness $userBusiness) {
return e($userBusiness->user_level_name);
})
->addColumn('is_qual_kp', function (UserBusiness $userBusiness) {
return TreeHelperOptimized::generateQualKPBadge($userBusiness);
})
->addColumn('sales_volume_KP_points', function (UserBusiness $userBusiness) {
return TreeHelperOptimized::generateSalesVolumeDisplay($userBusiness, 'points');
})
->addColumn('sales_volume_total', function (UserBusiness $userBusiness) {
return TreeHelperOptimized::generateSalesVolumeDisplay($userBusiness, 'total');
})
->addColumn('email', function (UserBusiness $userBusiness) {
return e($userBusiness->email);
})
->addColumn('first_name', function (UserBusiness $userBusiness) {
return e($userBusiness->first_name);
})
->addColumn('last_name', function (UserBusiness $userBusiness) {
return e($userBusiness->last_name);
})
->addColumn('sponsor', function (UserBusiness $userBusiness) {
return TreeHelperOptimized::generateSponsorDisplay($userBusiness);
})
->addColumn('active_account', function (UserBusiness $userBusiness) {
return get_active_badge($userBusiness->active_account);
})
->addColumn('next_level_qualified', function (UserBusiness $userBusiness) {
return NextLevelBadgeHelper::generateBadgeFromUserBusiness($userBusiness);
})
->addColumn('payment_account_date', function (UserBusiness $userBusiness) {
return $userBusiness->active_date ? formatDate($userBusiness->active_date) : "-";
})
->filterColumn('m_account', function ($query, $keyword) {
if ($keyword != "") {
$query->whereRaw("user_businesses.m_account LIKE ?", '%' . $keyword . '%');
}
})
->filterColumn('first_name', function ($query, $keyword) {
if ($keyword != "") {
$query->whereRaw("user_businesses.first_name LIKE ?", '%' . $keyword . '%');
}
})
->filterColumn('last_name', function ($query, $keyword) {
if ($keyword != "") {
$query->whereRaw("user_businesses.last_name LIKE ?", '%' . $keyword . '%');
}
})
->filterColumn('email', function ($query, $keyword) {
if ($keyword != "") {
$query->whereRaw("user_businesses.email LIKE ?", '%' . $keyword . '%');
}
})
->orderColumn('id', 'id $1')
->orderColumn('m_account', 'm_account $1')
->orderColumn('email', 'email $1')
->orderColumn('first_name', 'first_name $1')
->orderColumn('last_name', 'last_name $1')
->orderColumn('active_account', 'payment_account $1')
->rawColumns(['id', 'is_qual_kp', 'sales_volume_KP_points', 'sales_volume_total', 'sponsor', 'active_account', 'next_level_qualified'])
->make(true);
}
/**
* Optimierte Currently-Datatable mit Repository Pattern
*/
private function userCurrentlyDatatableOptimized(): JsonResponse
{
$repository = new BusinessUserRepository($this->month, $this->year);
// Nutze Repository für optimierte Abfragen
$query = $this->initCurrentlySearchOptimized();
return \DataTables::eloquent($query)
->addColumn('id', function (User $user) {
return TreeHelperOptimized::generateActionButtons($user->id);
})
->addColumn('m_account', function (User $user) {
return $user->account ? e($user->account->m_account) : '';
})
->addColumn('user_level', function (User $user) {
return $user->user_level ? e($user->user_level->getLang('name')) : '';
})
->addColumn('is_qual_kp', function (User $user) {
return TreeHelperOptimized::generateQualKPBadgeForUser($user, $this->month, $this->year);
})
->addColumn('sales_volume_KP_points', function (User $user) {
return TreeHelperOptimized::generateSalesVolumeDisplayForUser($user, 'points', $this->month, $this->year);
})
->addColumn('sales_volume_total', function (User $user) {
return TreeHelperOptimized::generateSalesVolumeDisplayForUser($user, 'total', $this->month, $this->year);
})
->addColumn('email', function (User $user) {
return e($user->email);
})
->addColumn('first_name', function (User $user) {
return $user->account ? e($user->account->first_name) : '';
})
->addColumn('last_name', function (User $user) {
return $user->account ? e($user->account->last_name) : '';
})
->addColumn('sponsor', function (User $user) {
return TreeHelperOptimized::generateSponsorDisplayForUser($user);
})
->addColumn('active_account', function (User $user) {
return get_active_badge($user->isActiveAccount());
})
->addColumn('next_level_qualified', function (User $user) {
// Für Live-DataTable: Verwende bereits berechnete Daten wenn verfügbar
$userBusiness = UserBusiness::where('user_id', $user->id)
->where('month', $this->month)
->where('year', $this->year)
->first();
if ($userBusiness) {
return NextLevelBadgeHelper::generateBadgeFromUserBusiness($userBusiness);
}
return NextLevelBadgeHelper::renderNoDataBadge();
})
->addColumn('payment_account_date', function (User $user) {
return $user->payment_account ? $user->getPaymentAccountDateFormat(false) : "-";
})
->filterColumn('m_account', function ($query, $keyword) {
if ($keyword != "") {
$query->whereRaw("user_accounts.m_account LIKE ?", '%' . $keyword . '%');
}
})
->filterColumn('first_name', function ($query, $keyword) {
if ($keyword != "") {
$query->whereRaw("user_accounts.first_name LIKE ?", '%' . $keyword . '%');
}
})
->filterColumn('last_name', function ($query, $keyword) {
if ($keyword != "") {
$query->whereRaw("user_accounts.last_name LIKE ?", '%' . $keyword . '%');
}
})
->filterColumn('email', function ($query, $keyword) {
if ($keyword != "") {
$query->whereRaw("users.email LIKE ?", '%' . $keyword . '%');
}
})
->orderColumn('id', 'users.id $1')
->orderColumn('m_account', 'user_accounts.m_account $1')
->orderColumn('first_name', 'user_accounts.first_name $1')
->orderColumn('last_name', 'user_accounts.last_name $1')
->orderColumn('email', 'users.email $1')
->orderColumn('active_account', 'users.payment_account $1')
->rawColumns(['id', 'is_qual_kp', 'sales_volume_KP_points', 'sales_volume_total', 'sponsor', 'active_account', 'next_level_qualified'])
->make(true);
}
// ===== PRIVATE HELPER METHODS =====
/**
* Optimierte Stored Search Query
*/
private function initStoredSearchOptimized()
{
$this->setFilterVars();
$query = UserBusiness::select('user_businesses.*')
->where('month', $this->month)
->where('year', $this->year);
$activeFilter = Request::get('business_user_filter_active') ?: session('business_user_filter_active');
if ($activeFilter == 1) {
$query->where('user_businesses.active_account', 1);
} elseif ($activeFilter == 2) {
$query->where('user_businesses.active_account', 0);
}
// activeFilter == 3 bedeutet alle (keine weitere Einschränkung)
$levelFilter = Request::get('business_user_filter_level') ?: session('business_user_filter_level');
if ($levelFilter && $levelFilter != 0) {
$query->where('user_businesses.m_level_id', $levelFilter);
}
$nextLevelFilter = Request::get('business_user_filter_next_level') ?: session('business_user_filter_next_level');
if ($nextLevelFilter && $nextLevelFilter != 0) {
switch ($nextLevelFilter) {
case 1: // Qualifiziert (grün) - hat next_qual_user_level
$query->whereNotNull('user_businesses.next_qual_user_level')
->where('user_businesses.next_qual_user_level', '!=', '[]');
break;
case 2: // In Arbeit (gelb) - hat next_can_user_level aber kein next_qual_user_level
$query->where(function ($q) {
$q->whereNull('user_businesses.next_qual_user_level')
->orWhere('user_businesses.next_qual_user_level', '=', '[]');
})
->whereNotNull('user_businesses.next_can_user_level')
->where('user_businesses.next_can_user_level', '!=', '[]');
break;
case 3: // Kein Level (rot) - hat weder next_qual noch next_can
$query->where(function ($q) {
$q->where(function ($q1) {
$q1->whereNull('user_businesses.next_qual_user_level')
->orWhere('user_businesses.next_qual_user_level', '=', '[]');
})
->where(function ($q2) {
$q2->whereNull('user_businesses.next_can_user_level')
->orWhere('user_businesses.next_can_user_level', '=', '[]');
});
});
break;
}
}
return $query;
}
/**
* Optimierte Currently Search Query mit besseren Joins
*/
private function initCurrentlySearchOptimized()
{
$this->setFilterVars();
$query = User::with(['account', 'user_level', 'user_sponsor.account'])
->select('users.*', 'user_accounts.m_account', 'user_accounts.first_name', 'user_accounts.last_name')
->leftJoin('user_accounts', 'users.id', '=', 'user_accounts.id')
->where('users.deleted_at', '=', null)
->where('users.id', '!=', 1)
->where('users.admin', '<', 4)
->where('users.m_level', '!=', null)
->where('users.payment_account', '!=', null);
$activeFilter = Request::get('business_user_filter_active') ?: session('business_user_filter_active');
if ($activeFilter == 1) {
$query->where('users.payment_account', '>=', now());
} elseif ($activeFilter == 2) {
$query->where('users.payment_account', '<', now());
}
// activeFilter == 3 bedeutet alle (keine weitere Einschränkung)
$levelFilter = Request::get('business_user_filter_level') ?: session('business_user_filter_level');
if ($levelFilter && $levelFilter != 0) {
$query->where('users.m_level', $levelFilter);
}
// Next-Level-Filter wird bei Live-Berechnungen ignoriert (Performance-Gründe)
// Dieser Filter funktioniert nur mit gespeicherten Daten
$nextLevelFilter = Request::get('business_user_filter_next_level') ?: session('business_user_filter_next_level');
if ($nextLevelFilter && $nextLevelFilter != 0) {
Log::info("BusinessControllerOptimized: Next-Level-Filter bei Live-Berechnung ignoriert (Performance-Gründe)");
}
return $query;
}
/**
* Filter-Variablen setzen (identisch zur Original-Version)
*/
private function setFilterVars()
{
if (!session('business_user_filter_month')) {
session(['business_user_filter_month' => intval(date('m'))]);
}
if (!session('business_user_filter_year')) {
session(['business_user_filter_year' => intval(date('Y'))]);
}
if (!session('business_user_filter_active')) {
session(['business_user_filter_active' => 1]);
}
if (!session('business_user_filter_level')) {
session(['business_user_filter_level' => 0]);
}
if (!session('business_user_filter_next_level')) {
session(['business_user_filter_next_level' => 0]);
}
if (!session('business_user_filter_depiction')) {
session(['business_user_filter_depiction' => 'active']);
}
if (Request::get('business_user_filter_depiction')) {
session(['business_user_filter_depiction' => Request::get('business_user_filter_depiction')]);
}
if (Request::get('business_user_filter_name')) {
session(['business_user_filter_name' => Request::get('business_user_filter_name')]);
} else {
session(['business_user_filter_name' => '']);
}
if (Request::get('business_user_filter_active')) {
session(['business_user_filter_active' => Request::get('business_user_filter_active')]);
}
if (Request::get('business_user_filter_level')) {
session(['business_user_filter_level' => Request::get('business_user_filter_level')]);
} else {
session(['business_user_filter_level' => 0]);
}
if (Request::get('business_user_filter_next_level')) {
session(['business_user_filter_next_level' => Request::get('business_user_filter_next_level')]);
} else {
session(['business_user_filter_next_level' => 0]);
}
if (Request::get('business_user_filter_month')) {
session(['business_user_filter_month' => Request::get('business_user_filter_month')]);
}
if (Request::get('business_user_filter_year')) {
session(['business_user_filter_year' => Request::get('business_user_filter_year')]);
}
}
/**
* Formatiert Bytes in lesbare Einheiten
*/
private function formatBytes(int $bytes, int $precision = 2): string
{
$units = array('B', 'KB', 'MB', 'GB', 'TB');
for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
$bytes /= 1024;
}
return round($bytes, $precision) . ' ' . $units[$i];
}
/**
* Holt verfügbare User Level für Filter
*/
private function getFilterLevels(): array
{
$levels = [0 => 'Alle Level'];
$userLevels = \App\Models\UserLevel::orderBy('pos')->get(['id', 'name']);
foreach ($userLevels as $level) {
$levels[$level->id] = $level->name;
}
return $levels;
}
// Performance-optimierte Badge-Generierung wurde in NextLevelBadgeHelper ausgelagert
// Alte performance-lastige Methoden wurden entfernt um die Datatable-Performance zu verbessern
}