From d0a48e762f1d9ff81dfe9ae65e3fa1077b6a1bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Mon, 30 Mar 2026 17:16:01 +0300 Subject: [PATCH] feat: implement Nginx configuration management, PHP environment initialization, and extension management UI --- config/php.ini.template | 4 +- src/main/ipc/index.ts | 38 +++++------ .../src/components/PhpExtensionManager.tsx | 65 ++++++++++++------- 3 files changed, 62 insertions(+), 45 deletions(-) diff --git a/config/php.ini.template b/config/php.ini.template index 7ae54e2..c735f02 100644 --- a/config/php.ini.template +++ b/config/php.ini.template @@ -14,8 +14,8 @@ expose_php = On max_execution_time = 300 max_input_time = 120 memory_limit = 512M -error_reporting = E_ALL -display_errors = On +error_reporting = {{ERROR_REPORTING}} +display_errors = {{DISPLAY_ERRORS}} display_startup_errors = On log_errors = On log_errors_max_len = 1024 diff --git a/src/main/ipc/index.ts b/src/main/ipc/index.ts index 255fd53..9a91648 100644 --- a/src/main/ipc/index.ts +++ b/src/main/ipc/index.ts @@ -194,15 +194,27 @@ export function registerIpcHandlers(): void { // --- 1. Get extensions from local php.ini --- let extensionsList = '' + let errorReporting = 'E_ALL' + let displayErrors = 'On' + const localIniPath = path.join(phpDir, 'php.ini') const mustHaves = ['curl', 'mbstring', 'openssl', 'mysqli', 'pdo_mysql', 'gd', 'fileinfo', 'exif', 'intl', 'bz2', 'gettext', 'soap', 'xsl'] if (fs.existsSync(localIniPath)) { const localIniContent = fs.readFileSync(localIniPath, 'utf8') + + // 1. Get extensions const extMatches = localIniContent.match(/^\s*extension\s*=.*$/gm) if (extMatches) { extensionsList = extMatches.join('\n') } + + // 2. Get error settings + const erMatch = localIniContent.match(/^\s*error_reporting\s*=\s*(.+)$/m) + if (erMatch) errorReporting = erMatch[1].trim() + + const deMatch = localIniContent.match(/^\s*display_errors\s*=\s*(.+)$/m) + if (deMatch) displayErrors = deMatch[1].trim() } else { // Fallback formatting based on version const prefix = (phpVersion?.startsWith('5.') || phpVersion?.startsWith('7.')) ? 'php_' : '' @@ -215,7 +227,9 @@ export function registerIpcHandlers(): void { GD_EXT: gdExtName, SESSION_DIR: sessionDir, TEMP_DIR: tempDir, - EXTENSIONS: extensionsList + EXTENSIONS: extensionsList, + ERROR_REPORTING: errorReporting, + DISPLAY_ERRORS: displayErrors }) // Add a small delay to ensure previous instance (if any) is fully killed @@ -374,23 +388,10 @@ export function registerIpcHandlers(): void { ipcMain.handle('php:extensions:toggle', async (_event, { version, extName, enabled }) => { const result = await phpManagerService.toggleExtension(version, extName, enabled) if (result.success) { - // Automatically restart the PHP service if it's running const serviceName = `php:${version}` if (processManager.isServiceRunning(serviceName)) { - console.log(`Restarting ${serviceName} due to extension change...`) await processManager.stopService(serviceName) - // We need to re-run the start logic or just let the user do it? - // The user said "Proceed with the decision that you think is the most optimal" - // Optimal is to restart it exactly as it was. - // However, the start logic in 'services:start' has many parameters (ports, ini templates). - // It's better to just stop it and tell the user it needs to be started again, - // OR I can try to trigger the same start logic. - // Given the current architecture, I'll just stop it and return a message. - // Wait, I can't easily call 'services:start' from here without the event object. - // Actually, I can just not restart it here and let the renderer handle it if they want. - // NO, I'll just return that it's updated. PHP usually needs a restart anyway. - // I'll update the message to reflect that. - result.message += ". Please restart the PHP service to apply changes." + result.message += " (Service stopped for restart)" } } return result @@ -413,13 +414,12 @@ export function registerIpcHandlers(): void { const iniPath = path.join(phpDir, 'php.ini') fs.writeFileSync(iniPath, content) - // Return a result that indicates a restart is needed const serviceName = `php:${version}` - const isRunning = processManager.isServiceRunning(serviceName) - if (isRunning) { + if (processManager.isServiceRunning(serviceName)) { await processManager.stopService(serviceName) } - return { success: true, message: `php.ini saved.${isRunning ? ' Current PHP service stopped. Please restart to apply.' : ''}` } + + return { success: true, message: 'Configuration saved.' } }) // MariaDB Versions diff --git a/src/renderer/src/components/PhpExtensionManager.tsx b/src/renderer/src/components/PhpExtensionManager.tsx index a77fda1..4067fad 100644 --- a/src/renderer/src/components/PhpExtensionManager.tsx +++ b/src/renderer/src/components/PhpExtensionManager.tsx @@ -71,18 +71,34 @@ const PhpExtensionManager: React.FC = ({ open, onClose const handleSaveRaw = async () => { setIsSavingRaw(true) + Swal.fire({ + title: 'Yapılandırma Kaydediliyor', + text: 'PHP servisi yeniden başlatılıyor...', + allowOutsideClick: false, + didOpen: () => { + Swal.showLoading() + }, + background: '#1e1e1e', + color: '#fff' + }) + try { const result = await window.api.invoke('php:config:save', { version: phpVersion, content: rawConfig }) if (result.success) { + // Trigger restart + await window.api.invoke('services:start', `php:${phpVersion}`) + Swal.fire({ title: 'Başarılı', - text: result.message, + text: 'Yapılandırma kaydedildi ve servis yeniden başlatıldı.', icon: 'success', + timer: 2000, + showConfirmButton: false, background: '#1e1e1e', color: '#fff' }) setIsRawEditorOpen(false) - fetchExtensions() // Refresh extension list too + fetchExtensions() } } catch (error: any) { Swal.fire({ title: 'Hata', text: error.message, icon: 'error', background: '#1e1e1e', color: '#fff' }) @@ -99,36 +115,37 @@ const PhpExtensionManager: React.FC = ({ open, onClose const handleToggle = async (extName: string, enabled: boolean) => { setSaving(extName) + + // Show a non-blocking toast or a small overlay if we want, but for "Restart" let's be more explicit if it was running + const wasRunning = await window.api.invoke('service:status', `php:${phpVersion}`) === 'running' + + if (wasRunning) { + Swal.fire({ + title: 'Eklenti Ayarlanıyor', + text: `${extName} ${enabled ? 'aktif ediliyor' : 'devre dışı bırakılıyor'} ve PHP yeniden başlatılıyor...`, + allowOutsideClick: false, + didOpen: () => { + Swal.showLoading() + }, + background: '#1e1e1e', + color: '#fff' + }) + } + try { const result = await window.api.invoke('php:extensions:toggle', { version: phpVersion, extName, enabled }) if (result.success) { setExtensions(prev => prev.map(ext => ext.name === extName ? { ...ext, enabled } : ext)) - if (result.message.includes('restart')) { - Swal.fire({ - title: 'Bilgi', - text: result.message, - icon: 'info', - background: '#1e1e1e', - color: '#fff' - }) + + if (wasRunning) { + await window.api.invoke('services:start', `php:${phpVersion}`) + Swal.close() } } else { - Swal.fire({ - title: 'Hata', - text: result.message, - icon: 'error', - background: '#1e1e1e', - color: '#fff' - }) + Swal.fire({ title: 'Hata', text: result.message, icon: 'error', background: '#1e1e1e', color: '#fff' }) } } catch (error: any) { - Swal.fire({ - title: 'Hata', - text: error.message, - icon: 'error', - background: '#1e1e1e', - color: '#fff' - }) + Swal.fire({ title: 'Hata', text: error.message, icon: 'error', background: '#1e1e1e', color: '#fff' }) } finally { setSaving(null) }