HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/hi.naniguide.com/app/Http/Controllers/Admin/TranslationBulkController.php
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\TranslationLine;
use App\Models\TranslationLocale;
use App\Translation\TranslationKeyScanner;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

class TranslationBulkController extends Controller
{
    public function edit(Request $request, TranslationLocale $translation_locale)
    {
        $search = trim((string) $request->query('q', ''));
        $section = trim((string) $request->query('section', ''));
        $refresh = (bool) $request->boolean('refresh');

        $activeLocales = TranslationLocale::query()
            ->where('is_active', true)
            ->orderBy('code')
            ->get(['id', 'code', 'name']);

        $sourceLocale = $activeLocales->first(function ($locale) {
            $code = is_string($locale->code ?? null) ? trim((string) $locale->code) : '';
            return $code === 'en';
        });

        if (!$sourceLocale) {
            $sourceLocale = $activeLocales->first(function ($locale) {
                $code = is_string($locale->code ?? null) ? trim((string) $locale->code) : '';
                return str_starts_with($code, 'en_') || str_starts_with($code, 'en-');
            });
        }

        if (!$sourceLocale) {
            $sourceLocale = $activeLocales->first(function ($locale) {
                $name = is_string($locale->name ?? null) ? trim((string) $locale->name) : '';
                return $name !== '' && stripos($name, 'english') !== false;
            });
        }

        if (!$sourceLocale) {
            $sourceLocale = $activeLocales->first();
        }

        $scan = app(TranslationKeyScanner::class)->scanDetailed($refresh);
        $keys = (array) ($scan['keys'] ?? []);
        $filesByKey = (array) ($scan['filesByKey'] ?? []);

        if ($search !== '') {
            $keys = array_values(array_filter($keys, function ($k) use ($search) {
                return str_contains(mb_strtolower((string) $k), mb_strtolower($search));
            }));
        }

        $sectionsByKey = [];
        foreach ($keys as $rawKey) {
            $files = $filesByKey[$rawKey] ?? [];
            $files = is_array($files) ? $files : [];
            $sectionsByKey[$rawKey] = $this->determineSection($files);
        }

        $sectionOrder = ['Sidebar', 'Login page', 'Register page', 'Dashboard page', 'Users page', 'Invoices', 'Coupons', 'Plans', 'Payment Methods', 'Vat/Tax', 'Customers', 'Groups', 'Campaigns', 'Email Lists', 'Email Validation', 'Delivery Servers', 'Sending Domains', 'Tracking Domains', 'Bounce Servers', 'Bounced Emails', 'Other'];
        $sections = array_values(array_unique(array_values($sectionsByKey)));

        $requiredSections = ['Login page', 'Register page', 'Campaigns', 'Email Lists', 'Email Validation', 'Customers', 'Groups'];
        $sections = array_values(array_unique(array_merge($requiredSections, $sections)));
        usort($sections, function ($a, $b) use ($sectionOrder) {
            $ai = array_search($a, $sectionOrder, true);
            $bi = array_search($b, $sectionOrder, true);
            $ai = $ai === false ? PHP_INT_MAX : $ai;
            $bi = $bi === false ? PHP_INT_MAX : $bi;

            if ($ai === $bi) {
                return strcasecmp((string) $a, (string) $b);
            }

            return $ai <=> $bi;
        });

        if ($section === '') {
            if (in_array('Sidebar', $sections, true)) {
                $section = 'Sidebar';
            } else {
                $section = $sections[0] ?? 'Other';
            }
        }

        $keys = array_values(array_filter($keys, fn ($k) => ($sectionsByKey[$k] ?? 'Other') === $section));

        $perPage = 25;
        $page = max(1, (int) $request->query('page', 1));
        $slice = array_slice($keys, ($page - 1) * $perPage, $perPage);

        $sourceCode = $sourceLocale?->code;
        $items = [];

        foreach ($slice as $rawKey) {
            $parsed = $this->parseKey($rawKey);

            $items[] = [
                'rawKey' => $rawKey,
                'group' => $parsed['group'],
                'key' => $parsed['key'],
                'source' => $sourceCode ? trans($rawKey, [], $sourceCode) : $rawKey,
                'section' => $section,
            ];
        }

        $paginator = new LengthAwarePaginator(
            $items,
            count($keys),
            $perPage,
            $page,
            [
                'path' => $request->url(),
                'query' => $request->query(),
            ]
        );

        $targetLines = TranslationLine::query()
            ->where('translation_locale_id', $translation_locale->id)
            ->where(function ($q) use ($items) {
                foreach ($items as $item) {
                    $q->orWhere(function ($sub) use ($item) {
                        $sub->where('group', $item['group'])
                            ->where('key', $item['key']);
                    });
                }
            })
            ->get(['group', 'key', 'text'])
            ->mapWithKeys(fn ($l) => [($l->group . '|' . $l->key) => $l->text]);

        return view('admin.translations.bulk.edit', [
            'translation_locale' => $translation_locale,
            'sourceLocale' => $sourceLocale,
            'rows' => $paginator,
            'targetLines' => $targetLines,
            'search' => $search,
            'sections' => $sections,
            'section' => $section,
        ]);
    }

    public function update(Request $request, TranslationLocale $translation_locale)
    {
        $validated = $request->validate([
            'translations' => ['nullable', 'array'],
            'translations.*' => ['nullable', 'string'],
        ]);

        $translations = (array) ($validated['translations'] ?? []);

        DB::transaction(function () use ($translations, $translation_locale) {
            foreach ($translations as $key => $value) {
                if (!is_string($key) || trim($key) === '') {
                    continue;
                }

                $parsed = $this->parseKey($key);
                $group = $parsed['group'];
                $innerKey = $parsed['key'];

                $value = is_string($value) ? trim($value) : '';

                if ($value === '') {
                    TranslationLine::query()
                        ->where('translation_locale_id', $translation_locale->id)
                        ->where('group', $group)
                        ->where('key', $innerKey)
                        ->delete();

                    continue;
                }

                TranslationLine::query()->updateOrCreate(
                    [
                        'translation_locale_id' => $translation_locale->id,
                        'group' => $group,
                        'key' => $innerKey,
                    ],
                    [
                        'text' => $value,
                    ]
                );
            }

            $translation_locale->touch();
        });

        $redirectQuery = array_filter([
            'section' => $request->input('section'),
            'q' => $request->input('q'),
        ], fn ($v) => is_string($v) && trim($v) !== '');

        return redirect()
            ->route('admin.translations.bulk.edit', [$translation_locale] + $redirectQuery)
            ->with('success', __('Translations saved.'));
    }

    private function parseKey(string $rawKey): array
    {
        $rawKey = trim($rawKey);

        if ($rawKey === '' || str_contains($rawKey, '::')) {
            return ['group' => '*', 'key' => $rawKey];
        }

        $parts = explode('.', $rawKey, 2);

        if (count($parts) === 2 && $parts[0] !== '' && $parts[1] !== '') {
            return ['group' => $parts[0], 'key' => $parts[1]];
        }

        return ['group' => '*', 'key' => $rawKey];
    }

    private function determineSection(array $files): string
    {
        $files = array_values(array_filter($files, fn ($p) => is_string($p) && trim($p) !== ''));

        foreach ($files as $p) {
            if (
                str_contains($p, 'resources/views/auth/login.blade.php') ||
                str_contains($p, 'resources/views/customer/auth/login.blade.php') ||
                str_contains($p, 'resources/views/admin/auth/login.blade.php')
            ) {
                return 'Login page';
            }
        }

        foreach ($files as $p) {
            if (
                str_contains($p, 'resources/views/auth/register.blade.php') ||
                str_contains($p, 'resources/views/customer/auth/register.blade.php')
            ) {
                return 'Register page';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/components/sidebar.blade.php') || str_contains($p, 'resources/views/layouts/admin.blade.php')) {
                return 'Sidebar';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/dashboard')) {
                return 'Dashboard page';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/users')) {
                return 'Users page';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/invoices')) {
                return 'Invoices';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/coupons')) {
                return 'Coupons';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/plans')) {
                return 'Plans';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/payment-methods')) {
                return 'Payment Methods';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/vat-tax')) {
                return 'Vat/Tax';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/customers')) {
                return 'Customers';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/user-groups') || str_contains($p, 'resources/views/admin/customer-groups')) {
                return 'Groups';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/campaigns')) {
                return 'Campaigns';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/lists')) {
                return 'Email Lists';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/email-validation')) {
                return 'Email Validation';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/delivery-servers')) {
                return 'Delivery Servers';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/sending-domains')) {
                return 'Sending Domains';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/tracking-domains')) {
                return 'Tracking Domains';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/bounce-servers')) {
                return 'Bounce Servers';
            }
        }

        foreach ($files as $p) {
            if (str_contains($p, 'resources/views/admin/bounced-emails')) {
                return 'Bounced Emails';
            }
        }

        return 'Other';
    }
}