feat(payments): Anbieter-Gerüst core/payments mit PayPal Orders v2
- ProviderInterface/AbstractProvider: Vorgang mit Uhrzeit+Session (payment_transactions), Mail und Warenkorb erst nach Zahlung, idempotentes markPaid, Betragsabgleich, shop_event + PG payment_log - Secrets verschluesselt (libsodium) in MySQL, Schluessel ausserhalb Docroot - Cashdesk: ?payment_return/?payment_cancel, Pending-Riegel, zahlung_erst_spaeter() - Backend Zahlart-Editor: Einstellungen speichern (war ohne Empfaenger), Secret-Felder - payment_webhook.php (Standalone), cli.php (init-key, secret, reconcile, status) - PayPal-v2-Blaupause vom Juli entfernt
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Payments;
|
||||
|
||||
/**
|
||||
* Findet den Anbieter zu einem payment_methods.module.
|
||||
*
|
||||
* Konvention: core/payments/providers/<module>/Provider.php mit Klasse
|
||||
* Payments\Providers\<Module in StudlyCase>\Provider
|
||||
* Beispiel: module 'paypal_v2' -> Payments\Providers\PaypalV2\Provider
|
||||
*
|
||||
* Neuer Anbieter = neues Verzeichnis, sonst nichts.
|
||||
*/
|
||||
final class Registry
|
||||
{
|
||||
/** @var array<string,ProviderInterface|null> */
|
||||
private static array $cache = [];
|
||||
|
||||
public static function has(string $module): bool
|
||||
{
|
||||
$module = self::clean($module);
|
||||
return $module !== '' && \is_file(self::dir($module) . '/Provider.php');
|
||||
}
|
||||
|
||||
public static function get(string $module, object $base): ?ProviderInterface
|
||||
{
|
||||
$module = self::clean($module);
|
||||
if ($module === '') {
|
||||
return null;
|
||||
}
|
||||
if (\array_key_exists($module, self::$cache)) {
|
||||
return self::$cache[$module];
|
||||
}
|
||||
$file = self::dir($module) . '/Provider.php';
|
||||
if (!\is_file($file)) {
|
||||
return self::$cache[$module] = null;
|
||||
}
|
||||
self::requireCore();
|
||||
require_once $file;
|
||||
$class = 'Payments\\Providers\\' . self::studly($module) . '\\Provider';
|
||||
if (!\class_exists($class)) {
|
||||
\error_log('Payments: Provider-Klasse fehlt: ' . $class);
|
||||
return self::$cache[$module] = null;
|
||||
}
|
||||
$p = new $class($base);
|
||||
return self::$cache[$module] = ($p instanceof ProviderInterface ? $p : null);
|
||||
}
|
||||
|
||||
/** Alle installierten Anbieter (fuer Backend-Liste und Abgleicher). @return list<string> */
|
||||
public static function all(): array
|
||||
{
|
||||
$out = [];
|
||||
foreach (\glob(__DIR__ . '/providers/*/Provider.php') ?: [] as $f) {
|
||||
$out[] = \basename(\dirname($f));
|
||||
}
|
||||
\sort($out);
|
||||
return $out;
|
||||
}
|
||||
|
||||
public static function requireCore(): void
|
||||
{
|
||||
foreach (['ProviderInterface', 'Result', 'Secrets', 'Log', 'AbstractProvider'] as $c) {
|
||||
require_once __DIR__ . '/' . $c . '.php';
|
||||
}
|
||||
}
|
||||
|
||||
private static function dir(string $module): string
|
||||
{
|
||||
return __DIR__ . '/providers/' . $module;
|
||||
}
|
||||
|
||||
private static function clean(string $module): string
|
||||
{
|
||||
return \preg_match('/^[a-z0-9_]+$/', $module) ? $module : '';
|
||||
}
|
||||
|
||||
private static function studly(string $module): string
|
||||
{
|
||||
return \str_replace('_', '', \ucwords($module, '_'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user