Compare commits
4 Commits
68d544b9c3
...
1873486d13
| Author | SHA1 | Date | |
|---|---|---|---|
| 1873486d13 | |||
| 5d3ea6d787 | |||
| 834527647d | |||
| 11f99caf42 |
@@ -3,8 +3,8 @@
|
||||
namespace App\Filament\Clusters\Cards\CardOrders\Pages;
|
||||
|
||||
use App\Filament\Clusters\Cards\CardOrders\CardOrderResource;
|
||||
use App\Modules\CardOrder\Repositories\CardOrderRepository;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
class CreateCardOrder extends CreateRecord
|
||||
{
|
||||
@@ -14,12 +14,14 @@ class CreateCardOrder extends CreateRecord
|
||||
{
|
||||
$defaultUrl = $this->getResource()::getUrl('index');
|
||||
|
||||
return $defaultUrl;
|
||||
/** @var \App\Modules\CardOrder\Models\CardOrder */
|
||||
$record = $this->record;
|
||||
|
||||
// $payment = (new OnlinePaymentRepo)->payCardOrder($resource);
|
||||
$OnlinePayment = CardOrderRepository::make()
|
||||
->createOnlinePaymentOrder($record);
|
||||
|
||||
// $payment['status'] === 'success'
|
||||
// ? URL::remote($payment['url'])
|
||||
// : $defaultUrl;
|
||||
return $OnlinePayment->successful()
|
||||
? $OnlinePayment->paymentLink()
|
||||
: $defaultUrl;
|
||||
}
|
||||
}
|
||||
|
||||
10
app/Modules/AppHelpers/Contracts/HasFailedMethod.php
Normal file
10
app/Modules/AppHelpers/Contracts/HasFailedMethod.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\AppHelpers\Contracts;
|
||||
|
||||
interface HasOnlinePaymentStatusFields
|
||||
{
|
||||
public function failed(): bool;
|
||||
|
||||
public function successful(): bool;
|
||||
}
|
||||
@@ -77,4 +77,20 @@ class Branch extends Model
|
||||
{
|
||||
return $this->belongsToMany(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing username
|
||||
*/
|
||||
public function billingUsername(): string
|
||||
{
|
||||
return $this->billing_username ?: '-';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing password
|
||||
*/
|
||||
public function billingPassword(): string
|
||||
{
|
||||
return $this->billing_password ?: '-';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,16 @@ class CardOrderModule implements ModuleContract
|
||||
name: 'Branch',
|
||||
message: 'This module is used for branches.',
|
||||
),
|
||||
new ModulePackage(
|
||||
type: ModulePackageType::MODULE,
|
||||
name: 'OrderStatus',
|
||||
message: 'Supports orders.',
|
||||
),
|
||||
new ModulePackage(
|
||||
type: ModulePackageType::MODULE,
|
||||
name: 'OnlinePayment',
|
||||
message: 'Is online payable.',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Models\User;
|
||||
use App\Modules\Branch\Interfaces\BelongsToBranch;
|
||||
use App\Modules\Branch\Models\Branch;
|
||||
use App\Modules\LoanOrder\Repositories\LoanOrderRepository;
|
||||
use App\Modules\OnlinePayment\Contracts\HasOnlinePayments;
|
||||
use App\Modules\OrderStatus\Interfaces\HasStatus;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
@@ -111,4 +112,12 @@ class CardOrder extends Model implements BelongsToBranch, HasStatus
|
||||
static::creating(LoanOrderRepository::creating());
|
||||
static::created(LoanOrderRepository::created());
|
||||
}
|
||||
|
||||
/**
|
||||
* Price for card
|
||||
*/
|
||||
public function priceAmount(): int|float|string
|
||||
{
|
||||
return $this->cardState->price ?? 32;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,32 @@
|
||||
|
||||
namespace App\Modules\CardOrder\Repositories;
|
||||
|
||||
class CardOrderRepository {}
|
||||
use App\Modules\CardOrder\Models\CardOrder;
|
||||
use App\Modules\HalkbankOnlinePayment\Repositories\HalkbankOnlinePaymentRepository;
|
||||
use App\Modules\Makeable;
|
||||
use App\Modules\OnlinePayment\Repositories\OnlinePaymentRepository;
|
||||
|
||||
class CardOrderRepository
|
||||
{
|
||||
use Makeable;
|
||||
|
||||
/**
|
||||
* Create online payment order
|
||||
*/
|
||||
public function createOnlinePaymentOrder(CardOrder $record): OnlinePaymentRepository
|
||||
{
|
||||
/** @var \App\Modules\Branch\Models\Branch */
|
||||
$branch = $record->branch;
|
||||
|
||||
return OnlinePaymentRepository::make(relatedModel: $record)
|
||||
->paymentProvider(
|
||||
HalkbankOnlinePaymentRepository::make()
|
||||
->setUsername($branch->billingUsername())
|
||||
->setPassword($branch->billingPassword())
|
||||
->setAmount($record->priceAmount())
|
||||
->setReturnUrl(route('halkbank-online-payment.store'))
|
||||
->setDescription('Kart tölegi')
|
||||
)
|
||||
->sendRequest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'username' => 'hello',
|
||||
'password' => '',
|
||||
'returnUrl' => '',
|
||||
];
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\HalkbankOnlinePayment\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class HalkbankOnlinePaymentController extends Controller
|
||||
{
|
||||
public function store(Request $request): View
|
||||
{
|
||||
$request->validate([
|
||||
'orderId' => ['required', 'string', 'max:50', 'exists:online_payment_histories,orderId'],
|
||||
]);
|
||||
|
||||
return view('welcome');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\HalkbankOnlinePayment;
|
||||
|
||||
use App\Modules\Makeable;
|
||||
use App\Modules\ModuleContract;
|
||||
|
||||
class HalkbankOnlinePaymentModule implements ModuleContract
|
||||
{
|
||||
use Makeable;
|
||||
|
||||
/**
|
||||
* Module is enabled
|
||||
*/
|
||||
protected bool $enabled = true;
|
||||
|
||||
/**
|
||||
* Check if is module enabled
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable module
|
||||
*/
|
||||
public function disable(): void
|
||||
{
|
||||
$this->enabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable module
|
||||
*/
|
||||
public function enable(): void
|
||||
{
|
||||
$this->enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if module has a filament resource
|
||||
*/
|
||||
public function hasFilamentResource(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get module composer requirements
|
||||
*/
|
||||
public function getComposerRequirements(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get module composer suggestions
|
||||
*/
|
||||
public function getComposerSuggestions(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\HalkbankOnlinePayment\Repositories;
|
||||
|
||||
use App\Modules\Makeable;
|
||||
use App\Modules\OnlinePayment\Contracts\PaymentProviderContract;
|
||||
use Exception;
|
||||
use GuzzleHttp\Psr7\Response as GuzzleResponse;
|
||||
use Illuminate\Http\Client\Response;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class HalkbankOnlinePaymentRepository implements PaymentProviderContract
|
||||
{
|
||||
use Makeable;
|
||||
|
||||
public function __construct(
|
||||
protected string $username = '',
|
||||
protected string $password = '',
|
||||
protected int|float|string $amount = '',
|
||||
protected int|string $orderNumber = '',
|
||||
protected string $returnUrl = '',
|
||||
protected string $description = '',
|
||||
) {
|
||||
$this->username = config()->string('module.halkbank-online-payment.username');
|
||||
$this->password = config()->string('module.halkbank-online-payment.password');
|
||||
$this->returnUrl = config()->string('module.halkbank-online-payment.returnUrl');
|
||||
$this->orderNumber = $this->generateOrderNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send request to gatewat
|
||||
*/
|
||||
public function sendRequest(): Response
|
||||
{
|
||||
try {
|
||||
$paymentResponse = Http::get('https://mpi.gov.tm/payment/rest/register.do', [
|
||||
'orderNumber' => $this->orderNumber,
|
||||
'amount' => $this->formatAmount($this->amount),
|
||||
'currency' => 934,
|
||||
'language' => 'ru',
|
||||
'userName' => $this->username,
|
||||
'password' => $this->password,
|
||||
'returnUrl' => $this->returnUrl,
|
||||
'pageView' => 'DESKTOP',
|
||||
'description' => $this->description,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
Config::set('logging.channels.halkbank_payment_error', [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/halkbank_payment_error.log'),
|
||||
'level' => 'debug',
|
||||
]);
|
||||
|
||||
Log::channel('halkbank_payment_error')
|
||||
->error('Payment error', [
|
||||
'response' => [
|
||||
'error' => $e->getMessage(),
|
||||
'file_line' => $e->getFile().':'.$e->getLine(),
|
||||
],
|
||||
]);
|
||||
|
||||
return new Response(new GuzzleResponse(
|
||||
503,
|
||||
['Content-Type' => 'application/json'],
|
||||
sprintf('{"errorCode":"1","errorMessage":"%s"}', $e->getMessage())
|
||||
));
|
||||
}
|
||||
|
||||
return $paymentResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format amount to match requirements
|
||||
*/
|
||||
public function formatAmount(int|float|string $amount): string
|
||||
{
|
||||
return number_format(floatval($amount), 2, '', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get username
|
||||
*/
|
||||
public function username(): string
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get password
|
||||
*/
|
||||
public function password(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get amount
|
||||
*/
|
||||
public function amount(): int|float|string
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get order number
|
||||
*/
|
||||
public function orderNumber(): int|string
|
||||
{
|
||||
return $this->orderNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set return url
|
||||
*/
|
||||
public function returnUrl(): string
|
||||
{
|
||||
return $this->returnUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set description
|
||||
*/
|
||||
public function description(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set username
|
||||
*/
|
||||
public function setUsername(string $username): self
|
||||
{
|
||||
$this->username = $username;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set password
|
||||
*/
|
||||
public function setPassword(string $password): self
|
||||
{
|
||||
$this->password = $password;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set amoutn
|
||||
*/
|
||||
public function setAmount(int|float|string $amount): self
|
||||
{
|
||||
$this->amount = $amount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order number
|
||||
*/
|
||||
public function setOrderNumber(int|string $orderNumber): self
|
||||
{
|
||||
$this->orderNumber = $orderNumber;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set return url
|
||||
*/
|
||||
public function setReturnUrl(string $returnUrl): self
|
||||
{
|
||||
$this->returnUrl = $returnUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set description
|
||||
*/
|
||||
public function setDescription(string $description): self
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate order number for payment
|
||||
*/
|
||||
public function generateOrderNumber(): string
|
||||
{
|
||||
return date('dmyHis');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
use App\Modules\HalkbankOnlinePayment\Controllers\HalkbankOnlinePaymentController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('halkbank-online-payment-store', [HalkbankOnlinePaymentController::class, 'store'])
|
||||
->name('halkbank-online-payment.store');
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\OnlinePayment\Contracts;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
*/
|
||||
interface HasOnlinePayments {}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\OnlinePayment\Contracts;
|
||||
|
||||
use Illuminate\Http\Client\Response;
|
||||
|
||||
interface PaymentProviderContract
|
||||
{
|
||||
public function sendRequest(): Response;
|
||||
|
||||
public function orderNumber(): int|string;
|
||||
|
||||
public function amount(): int|float|string;
|
||||
|
||||
public function description(): string;
|
||||
|
||||
public function returnUrl(): string;
|
||||
|
||||
public function username(): string;
|
||||
}
|
||||
@@ -26,7 +26,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
* @property string $username
|
||||
* @property int $online_paymantable_id
|
||||
* @property string $online_paymantable_type
|
||||
* @property ?array $api_response
|
||||
* @property ?array<string, mixed> $api_response
|
||||
* @property \Illuminate\Support\Carbon $created_at
|
||||
* @property \Illuminate\Support\Carbon $updated_at
|
||||
*/
|
||||
|
||||
@@ -2,13 +2,18 @@
|
||||
|
||||
namespace App\Modules\OnlinePayment\Repositories;
|
||||
|
||||
use App\Modules\CardOrder\Models\CardOrder;
|
||||
use App\Modules\AppHelpers\Contracts\HasOnlinePaymentStatusFields;
|
||||
use App\Modules\Makeable;
|
||||
use App\Modules\OnlinePayment\Contracts\HasOnlinePayments;
|
||||
use App\Modules\OnlinePayment\Contracts\PaymentProviderContract;
|
||||
use App\Modules\OnlinePayment\Models\OnlinePayment;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Client\Response;
|
||||
|
||||
class OnlinePaymentRepository
|
||||
class OnlinePaymentRepository implements HasOnlinePaymentStatusFields
|
||||
{
|
||||
use Makeable;
|
||||
|
||||
/**
|
||||
* Pending online payments
|
||||
*/
|
||||
@@ -24,7 +29,47 @@ class OnlinePaymentRepository
|
||||
*/
|
||||
public const PAID = 'paid';
|
||||
|
||||
/**
|
||||
/**
|
||||
* Related model
|
||||
*/
|
||||
protected ?Model $relatedModel;
|
||||
|
||||
/**
|
||||
* Payment provider
|
||||
*/
|
||||
protected PaymentProviderContract $provider;
|
||||
|
||||
/**
|
||||
* Response
|
||||
*/
|
||||
protected Response $response;
|
||||
|
||||
/**
|
||||
* If payment is successful
|
||||
*/
|
||||
protected bool $successful;
|
||||
|
||||
/**
|
||||
* If payment has failed
|
||||
*/
|
||||
protected bool $failed;
|
||||
|
||||
/**
|
||||
* Payment order id
|
||||
*/
|
||||
protected string $orderId;
|
||||
|
||||
/**
|
||||
* Online payment link
|
||||
*/
|
||||
protected string $paymentLink;
|
||||
|
||||
public function __construct(?Model $relatedModel)
|
||||
{
|
||||
$this->relatedModel = $relatedModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status Values
|
||||
*
|
||||
* @return array<null|string, string>
|
||||
@@ -39,71 +84,6 @@ class OnlinePaymentRepository
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set price
|
||||
*/
|
||||
public function getPrice(int|float|string $price): string
|
||||
{
|
||||
return number_format(floatval($price), 2, '', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Pay card order
|
||||
*
|
||||
* @param mixed $resource
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function payCardOrder()
|
||||
{
|
||||
$orderNumber = $this->generateOrderNumber();
|
||||
|
||||
// $paymentResponse = Http::get('https://mpi.gov.tm/payment/rest/register.do', [
|
||||
// 'orderNumber' => $orderNumber,
|
||||
// 'amount' => $this->getPrice($resource->priceAmount()),
|
||||
// 'currency' => 934,
|
||||
// 'language' => 'ru',
|
||||
// 'userName' => $resource->branch->billing_username,
|
||||
// 'password' => $resource->branch->billing_password,
|
||||
// 'returnUrl' => route('online-payment-store'),
|
||||
// 'pageView' => 'DESKTOP',
|
||||
// 'description' => 'Kart tölegi',
|
||||
// ])->onError(function ($response) {
|
||||
// Log::channel('halkbank_payment_error')
|
||||
// ->error('Payment error', [
|
||||
// 'response' => [
|
||||
// 'body' => $response->body(),
|
||||
// ],
|
||||
// ]);
|
||||
// });
|
||||
|
||||
// if ($paymentResponse->failed()) {
|
||||
// return [
|
||||
// 'status' => 'failed',
|
||||
// 'url' => '',
|
||||
// ];
|
||||
// }
|
||||
|
||||
// $onlinePaymentHistory = new OnlinePayment;
|
||||
// $onlinePaymentHistory->online_paymantable_id = $resource->really();
|
||||
// $onlinePaymentHistory->online_paymantable_type = CardOrder::class;
|
||||
// $onlinePaymentHistory->amount = $resource->priceAmount();
|
||||
// $onlinePaymentHistory->orderNumber = $orderNumber;
|
||||
// $onlinePaymentHistory->description = 'Kart tölegi';
|
||||
// $onlinePaymentHistory->orderId = $paymentResponse['orderId'];
|
||||
// $onlinePaymentHistory->formUrl = $paymentResponse['formUrl'];
|
||||
// $onlinePaymentHistory->successUrl = route('online-payment-store');
|
||||
// $onlinePaymentHistory->errorUrl = route('online-payment-store');
|
||||
// $onlinePaymentHistory->api_client = 'billing_username';
|
||||
// $onlinePaymentHistory->username = $resource->branch->billing_username;
|
||||
// $onlinePaymentHistory->paymentStatus = self::PENDING;
|
||||
// $onlinePaymentHistory->save();
|
||||
|
||||
// return [
|
||||
// 'status' => 'success',
|
||||
// 'url' => $paymentResponse['formUrl'],
|
||||
// ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate order number for payment
|
||||
*/
|
||||
@@ -111,4 +91,96 @@ class OnlinePaymentRepository
|
||||
{
|
||||
return date('dmyHis');
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment provder
|
||||
*/
|
||||
public function paymentProvider(PaymentProviderContract $provider): self
|
||||
{
|
||||
$this->provider = $provider;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If payment has been successfull
|
||||
*/
|
||||
public function successful(): bool
|
||||
{
|
||||
return $this->successful;
|
||||
}
|
||||
|
||||
/**
|
||||
* If payment has been a failure
|
||||
*/
|
||||
public function failed(): bool
|
||||
{
|
||||
return $this->failed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set respond results
|
||||
*/
|
||||
public function setResponseResults(bool $result): void
|
||||
{
|
||||
$this->successful = $result;
|
||||
$this->failed = ! $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send request via provider
|
||||
*/
|
||||
public function sendRequest(): self
|
||||
{
|
||||
$this->response = $this->provider->sendRequest();
|
||||
|
||||
$this->failed = $this->response->failed();
|
||||
$this->successful = $this->response->successful();
|
||||
|
||||
if ($this->response['errorCode'] != 0) {
|
||||
$this->setResponseResults(false);
|
||||
}
|
||||
|
||||
if ($this->successful) {
|
||||
$this->orderId = string($this->response['orderId']);
|
||||
$this->paymentLink = string($this->response['formUrl']);
|
||||
|
||||
$this->createHistory();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment link
|
||||
*/
|
||||
public function paymentLink(): string
|
||||
{
|
||||
return $this->paymentLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create online payment history
|
||||
*/
|
||||
public function createHistory(): void
|
||||
{
|
||||
$data = [
|
||||
'amount' => $this->provider->amount(),
|
||||
'orderNumber' => $this->provider->orderNumber(),
|
||||
'description' => $this->provider->description(),
|
||||
'orderId' => $this->orderId,
|
||||
'formUrl' => $this->paymentLink,
|
||||
'successUrl' => $this->provider->returnUrl(),
|
||||
'errorUrl' => $this->provider->returnUrl(),
|
||||
'username' => $this->provider->username(),
|
||||
'paymentStatus' => self::PENDING,
|
||||
];
|
||||
|
||||
if ($this->relatedModel) {
|
||||
$data['online_paymantable_id'] = $this->relatedModel->id; // @phpstan-ignore-line
|
||||
$data['online_paymantable_type'] = $this->relatedModel::class;
|
||||
}
|
||||
|
||||
OnlinePayment::create($data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,12 +55,41 @@ function module_exists(string $moduleName): bool
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an anonymous class that acts as a dynamic object.
|
||||
*
|
||||
* @param mixed ...$arguments Key-value pairs passed as an associative array.
|
||||
* @return object Anonymous class instance with dynamic properties.
|
||||
* Cast to string
|
||||
*/
|
||||
function emptyClass(...$arguments): object
|
||||
function string(mixed $value): string
|
||||
{
|
||||
if (! is_string($value)) {
|
||||
throw new Exception('!!!Make it string!!!');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an anonymous dynamic object with both properties and callable methods.
|
||||
*
|
||||
* You can define any mix of:
|
||||
* - scalar or object properties
|
||||
* - closures (which become methods bound to $this)
|
||||
*
|
||||
* Example:
|
||||
* ```php
|
||||
* $user = emptyClass(
|
||||
* name: 'Ali',
|
||||
* greet: fn(): string => "Hello, {$this->name}",
|
||||
* setName: fn(string $n): void => $this->name = $n,
|
||||
* );
|
||||
*
|
||||
* echo $user->greet(); // Hello, Ali
|
||||
* $user->setName('Ahmet');
|
||||
* echo $user->greet(); // Hello, Ahmet
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* @param mixed ...$arguments Key-value pairs (property name => value or Closure)
|
||||
*/
|
||||
function emptyClass(mixed ...$arguments): object
|
||||
{
|
||||
/**
|
||||
* @var array<string, mixed> $arguments
|
||||
@@ -68,20 +97,25 @@ function emptyClass(...$arguments): object
|
||||
return new class($arguments)
|
||||
{
|
||||
/**
|
||||
* Internal data storage.
|
||||
* Internal data store.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private array $data = [];
|
||||
|
||||
/**
|
||||
* Constructor that sets properties.
|
||||
* Constructor that sets up dynamic properties and binds closures.
|
||||
*
|
||||
* @param array<string, mixed> $props
|
||||
*/
|
||||
public function __construct(array $props)
|
||||
{
|
||||
foreach ($props as $key => $value) {
|
||||
if ($value instanceof Closure) {
|
||||
/** @var Closure $value */
|
||||
$value = $value->bindTo($this, self::class);
|
||||
}
|
||||
|
||||
$this->data[$key] = $value;
|
||||
}
|
||||
}
|
||||
@@ -111,5 +145,27 @@ function emptyClass(...$arguments): object
|
||||
{
|
||||
return isset($this->data[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method caller — invokes stored closures as methods.
|
||||
*
|
||||
* @param array<int, mixed> $args
|
||||
*
|
||||
* @throws BadMethodCallException if the method does not exist or is not callable.
|
||||
*/
|
||||
public function __call(string $method, array $args): mixed
|
||||
{
|
||||
$callable = $this->data[$method] ?? null;
|
||||
|
||||
if ($callable instanceof Closure) {
|
||||
return $callable(...$args);
|
||||
}
|
||||
|
||||
throw new BadMethodCallException(sprintf(
|
||||
'Method %s() does not exist on %s.',
|
||||
$method,
|
||||
self::class
|
||||
));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user