Install the Package
composer require nikolag/core
Ensure your composer.json includes "laravel/framework": "^5.5|^6.0|^7.0|^8.0|^9.0|^10.0" as a dependency.
Publish Configuration
Publish the default config to config/nikolag.php:
php artisan vendor:publish --provider="Nikolag\Core\Providers\NikolagServiceProvider" --tag="config"
Define a Basic Gateway Integration
Create a new service class (e.g., app/Services/Payment/Gateway/StripeGateway.php) extending Nikolag\Core\Contracts\GatewayContract:
namespace App\Services\Payment\Gateway;
use Nikolag\Core\Contracts\GatewayContract;
use Nikolag\Core\Exceptions\GatewayException;
class StripeGateway implements GatewayContract
{
public function processPayment(array $data): array
{
// Implement Stripe-specific logic
return ['success' => true, 'transaction_id' => 'stripe_123'];
}
}
Register the Gateway
Bind the gateway in a service provider (e.g., app/Providers/AppServiceProvider.php):
public function register()
{
$this->app->bind(
\Nikolag\Core\Contracts\GatewayContract::class,
\App\Services\Payment\Gateway\StripeGateway::class
);
}
Use the Gateway
Inject GatewayContract into a controller or service and call processPayment():
use Nikolag\Core\Contracts\GatewayContract;
class PaymentController extends Controller
{
public function __construct(private GatewayContract $gateway) {}
public function charge(Request $request)
{
$result = $this->gateway->processPayment($request->all());
return response()->json($result);
}
}
Gateway Abstraction
GatewayContract for all payment gateways (e.g., Stripe, PayPal, Mollie).// config/nikolag.php
'default' => env('NIKOLAG_GATEWAY', 'stripe'),
'connections' => [
'stripe' => \App\Services\Payment\Gateway\StripeGateway::class,
'paypal' => \App\Services\Payment\Gateway\PayPalGateway::class,
],
$gateway = app(\Nikolag\Core\Contracts\GatewayContract::class);
// OR use the facade:
$result = \Nikolag\Core\Facades\Nikolag::gateway()->processPayment($data);
Transaction Handling
Nikolag\Core\Models\Transaction for gateway-specific fields:
namespace App\Models;
use Nikolag\Core\Models\Transaction as BaseTransaction;
class Transaction extends BaseTransaction
{
protected $casts = [
'stripe_id' => 'string',
'paypal_status' => 'string',
];
}
Nikolag\Core\Services\TransactionService to log transactions:
$transaction = app(\Nikolag\Core\Services\TransactionService::class)
->create(['amount' => 100, 'gateway' => 'stripe', 'metadata' => []]);
Webhook Processing
Nikolag\Core\Contracts\WebhookHandlerContract for gateway-specific webhooks:
namespace App\Services\Payment\Handlers;
use Nikolag\Core\Contracts\WebhookHandlerContract;
class StripeWebhookHandler implements WebhookHandlerContract
{
public function handle(array $payload): void
{
// Parse Stripe events (e.g., charge.succeeded)
}
}
config/nikolag.php:
'webhooks' => [
'stripe' => \App\Services\Payment\Handlers\StripeWebhookHandler::class,
],
Refunds and Captures
Nikolag\Core\Contracts\GatewayContract methods:
public function refund(string $transactionId, float $amount): array;
public function capture(string $transactionId, float $amount): array;
$refund = \Nikolag\Core\Facades\Nikolag::gateway()->refund($transactionId, 50);
Nikolag\Core\Services\CashierBridge to extend Cashier with custom gateways:
$user->newSubscription('premium', 'custom-plan')
->gateway('stripe')
->create($token);
GatewayContract in PHPUnit:
$this->mock(\Nikolag\Core\Contracts\GatewayContract::class, function ($mock) {
$mock->shouldReceive('processPayment')
->andReturn(['success' => true]);
});
Nikolag\Core\Logging\PaymentLogger for audit trails:
app(\Nikolag\Core\Logging\PaymentLogger::class)->log('payment.attempt', $data);
Configuration Overrides
nikolag.php in src/config for published configs. If using a custom path, override the provider’s getConfigPath():
// In a custom service provider
$this->mergeConfigFrom(__DIR__.'/../config/nikolag.php', 'nikolag');
Facade vs. Dependency Injection
// Anti-pattern: Mixing facades and DI
class PaymentService {
public function __construct(GatewayContract $gateway) {
$this->gateway = $gateway;
$this->fallback = \Nikolag\Core\Facades\Nikolag::gateway(); // Redundant!
}
}
Webhook Idempotency
Nikolag\Core\Services\IdempotencyService to deduplicate:
$idempotency = app(\Nikolag\Core\Services\IdempotencyService::class);
if (!$idempotency->isProcessed($payload['id'])) {
$handler->handle($payload);
$idempotency->markProcessed($payload['id']);
}
Transaction Model Binding
Transaction, ensure the model is bound in AppServiceProvider:
$this->app->bind(
\Nikolag\Core\Models\Transaction::class,
\App\Models\Transaction::class
);
Currency and Amount Handling
bcdiv($amount, '100', 2) for cents). The package does not enforce this by default.try {
$result = $gateway->processPayment($data);
} catch (\Nikolag\Core\Exceptions\GatewayException $e) {
\Log::error('Payment failed', ['gateway' => 'stripe', 'error' => $e->getMessage()]);
throw new \RuntimeException('Payment processing error', 0, $e);
}
Nikolag\Core\Debugging\WebhookValidator to validate payloads:
$validator = new \Nikolag\Core\Debugging\WebhookValidator($payload, 'stripe');
if (!$validator->isValid()) {
\Log::warning('Invalid webhook payload', ['errors' => $validator->errors()]);
}
Custom Traits
Nikolag\Core\Traits\HasGatewayConfig for shared gateway logic:
namespace App\Traits;
use Nikolag\Core\Traits\HasGatewayConfig;
trait StripeConfigurable
{
use HasGatewayConfig;
protected function getGatewayConfig(): array
{
return config('nikolag.connections.stripe');
}
}
Utility Classes
Nikolag\Core\Utilities\PaymentHelper for custom validation:
namespace App\Utilities;
use Nikolag\Core\Utilities\PaymentHelper
How can I help you explore Laravel packages today?