Newwebshop/app/Core/Hook.php

340 lines
11 KiB
PHP

<?php
/**
* Copyright seit 2024 Webshop System
*
* Hook-System für PrestaShop-Modul-Kompatibilität
*
* @author Webshop System
* @license GPL v3
*/
namespace App\Core;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Exception;
class Hook
{
private static $hooks = [];
private static $hookModules = [];
private static $initialized = false;
/**
* Hook-System initialisieren
*/
public static function init()
{
if (self::$initialized) {
return;
}
self::loadHooksFromDatabase();
self::$initialized = true;
}
/**
* Hook registrieren
*/
public static function register($hookName, $moduleName, $callback, $position = 0)
{
if (!isset(self::$hooks[$hookName])) {
self::$hooks[$hookName] = [];
}
self::$hooks[$hookName][] = [
'module' => $moduleName,
'callback' => $callback,
'position' => $position
];
// Nach Position sortieren
usort(self::$hooks[$hookName], function($a, $b) {
return $a['position'] - $b['position'];
});
// Hook in Datenbank speichern
self::saveHookToDatabase($hookName, $moduleName, $position);
}
/**
* Hook ausführen
*/
public static function exec($hookName, $params = [])
{
self::init();
$results = [];
if (isset(self::$hooks[$hookName])) {
foreach (self::$hooks[$hookName] as $hook) {
try {
$result = call_user_func($hook['callback'], $params);
if ($result !== null) {
$results[] = $result;
}
} catch (\Exception $e) {
error_log("Hook Fehler in {$hook['module']}: " . $e->getMessage());
}
}
}
return $results;
}
/**
* Hook mit Rückgabewert ausführen (für display-Hooks)
*/
public static function execWithReturn($hookName, $params = [])
{
self::init();
$output = '';
if (isset(self::$hooks[$hookName])) {
foreach (self::$hooks[$hookName] as $hook) {
try {
$result = call_user_func($hook['callback'], $params);
if (is_string($result)) {
$output .= $result;
}
} catch (\Exception $e) {
error_log("Hook Fehler in {$hook['module']}: " . $e->getMessage());
}
}
}
return $output;
}
/**
* Hook entfernen
*/
public static function unregister($hookName, $moduleName)
{
if (isset(self::$hooks[$hookName])) {
foreach (self::$hooks[$hookName] as $key => $hook) {
if ($hook['module'] === $moduleName) {
unset(self::$hooks[$hookName][$key]);
}
}
}
// Hook aus Datenbank entfernen
self::removeHookFromDatabase($hookName, $moduleName);
}
/**
* Verfügbare Hooks abrufen
*/
public static function getHooks()
{
self::init();
return array_keys(self::$hooks);
}
/**
* Module für einen Hook abrufen
*/
public static function getHookModules($hookName)
{
self::init();
if (isset(self::$hooks[$hookName])) {
return array_column(self::$hooks[$hookName], 'module');
}
return [];
}
/**
* Hooks aus Datenbank laden
*/
private static function loadHooksFromDatabase()
{
try {
$conn = DriverManager::getConnection([
'url' => getenv('DATABASE_URL') ?: 'mysql://root:password@localhost/webshop'
]);
$stmt = $conn->prepare('
SELECT hook_name, module_name, position
FROM ws_hook_module
WHERE active = 1
ORDER BY position ASC
');
$stmt->execute();
$hooks = $stmt->fetchAllAssociative();
foreach ($hooks as $hook) {
$moduleName = $hook['module_name'];
$hookName = $hook['hook_name'];
$position = $hook['position'];
// Module-Klasse laden
$moduleClass = self::getModuleClass($moduleName);
if ($moduleClass && method_exists($moduleClass, 'hook' . ucfirst($hookName))) {
$callback = [$moduleClass, 'hook' . ucfirst($hookName)];
self::register($hookName, $moduleName, $callback, $position);
}
}
} catch (Exception $e) {
error_log('Hook-Datenbank Fehler: ' . $e->getMessage());
}
}
/**
* Hook in Datenbank speichern
*/
private static function saveHookToDatabase($hookName, $moduleName, $position)
{
try {
$conn = DriverManager::getConnection([
'url' => getenv('DATABASE_URL') ?: 'mysql://root:password@localhost/webshop'
]);
$stmt = $conn->prepare('
INSERT INTO ws_hook_module (hook_name, module_name, position, active, created_at)
VALUES (?, ?, ?, 1, NOW())
ON DUPLICATE KEY UPDATE position = ?, active = 1, updated_at = NOW()
');
$stmt->execute([$hookName, $moduleName, $position, $position]);
} catch (Exception $e) {
error_log('Hook-Speicher Fehler: ' . $e->getMessage());
}
}
/**
* Hook aus Datenbank entfernen
*/
private static function removeHookFromDatabase($hookName, $moduleName)
{
try {
$conn = DriverManager::getConnection([
'url' => getenv('DATABASE_URL') ?: 'mysql://root:password@localhost/webshop'
]);
$stmt = $conn->prepare('
UPDATE ws_hook_module
SET active = 0, updated_at = NOW()
WHERE hook_name = ? AND module_name = ?
');
$stmt->execute([$hookName, $moduleName]);
} catch (Exception $e) {
error_log('Hook-Entfernung Fehler: ' . $e->getMessage());
}
}
/**
* Module-Klasse laden
*/
private static function getModuleClass($moduleName)
{
$modulePath = __DIR__ . '/../../modules/' . $moduleName . '/' . $moduleName . '.php';
if (file_exists($modulePath)) {
require_once $modulePath;
$className = ucfirst($moduleName);
if (class_exists($className)) {
return new $className();
}
}
return null;
}
/**
* Hook-Statistiken abrufen
*/
public static function getHookStatistics()
{
self::init();
$stats = [];
foreach (self::$hooks as $hookName => $hookList) {
$stats[$hookName] = count($hookList);
}
return $stats;
}
/**
* Hook-Liste für Admin-Interface
*/
public static function getHookList()
{
return [
// Display Hooks (Frontend)
'displayHeader' => 'Header-Bereich',
'displayTop' => 'Oberer Bereich',
'displayNav' => 'Navigation',
'displayNav1' => 'Navigation 1',
'displayNav2' => 'Navigation 2',
'displayTopColumn' => 'Obere Spalte',
'displayLeftColumn' => 'Linke Spalte',
'displayRightColumn' => 'Rechte Spalte',
'displayFooter' => 'Footer-Bereich',
'displayFooterAfter' => 'Footer nach',
'displayHome' => 'Startseite',
'displayHomeTab' => 'Startseite Tabs',
'displayHomeTabContent' => 'Startseite Tab-Inhalt',
// Product Hooks
'displayProductListReviews' => 'Produktliste Bewertungen',
'displayProductAdditionalInfo' => 'Produkt zusätzliche Info',
'displayProductPriceBlock' => 'Produkt Preis-Block',
'displayProductButtons' => 'Produkt Buttons',
'displayProductTab' => 'Produkt Tabs',
'displayProductTabContent' => 'Produkt Tab-Inhalt',
'displayProductListFunctionalButtons' => 'Produktliste Funktions-Buttons',
// Cart Hooks
'displayShoppingCart' => 'Warenkorb',
'displayShoppingCartFooter' => 'Warenkorb Footer',
'actionCartUpdateQuantityBefore' => 'Warenkorb Menge vor Update',
'actionCartUpdateQuantityAfter' => 'Warenkorb Menge nach Update',
'actionCartListOverride' => 'Warenkorb Liste überschreiben',
// Order Hooks
'displayOrderConfirmation' => 'Bestellbestätigung',
'displayOrderDetail' => 'Bestelldetails',
'actionOrderStatusUpdate' => 'Bestellstatus Update',
'actionValidateOrder' => 'Bestellung validieren',
// Customer Hooks
'displayCustomerAccount' => 'Kundenkonto',
'displayCustomerAccountForm' => 'Kundenkonto Formular',
'actionCustomerAccountAdd' => 'Kundenkonto hinzufügen',
'actionCustomerAccountUpdate' => 'Kundenkonto Update',
// Admin Hooks
'displayAdminOrder' => 'Admin Bestellung',
'displayAdminProducts' => 'Admin Produkte',
'actionAdminProductsControllerSaveAfter' => 'Admin Produkt nach Speichern',
'actionAdminCustomersControllerSaveAfter' => 'Admin Kunde nach Speichern',
// Payment Hooks
'displayPayment' => 'Zahlungsmethoden',
'displayPaymentReturn' => 'Zahlungsrückgabe',
'actionPaymentConfirmation' => 'Zahlungsbestätigung',
// Search Hooks
'displaySearch' => 'Suche',
'actionSearch' => 'Suchaktion',
'displaySearchResults' => 'Suchergebnisse',
// Newsletter Hooks
'displayNewsletterRegistration' => 'Newsletter Registrierung',
'actionNewsletterRegistrationAfter' => 'Newsletter nach Registrierung',
// Security Hooks
'actionAuthentication' => 'Authentifizierung',
'actionCustomerLogoutAfter' => 'Kunde nach Logout',
'actionAdminLoginControllerLoginAfter' => 'Admin nach Login'
];
}
}