fix: add ext-soap to Dockerfile and composer.json to resolve SoapClient not found error in production
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
# رفع خطای `Class "SoapClient" not found` در پرداخت ملت (سرور prod)
|
||||
|
||||
## پروژه
|
||||
|
||||
`clinicpro` (backend / infra — Docker image)
|
||||
|
||||
## زمینه
|
||||
|
||||
درگاه ملت (`MellatGateway`) در مسیر prod برای فراخوانی وبسرویس بانک از `new \SoapClient(...)` استفاده میکند (کلاس PHP از افزونه `ext-soap`). روی محیط لوکال (ddev) افزونه `soap` بهصورت پیشفرض نصب است، پس مشکلی دیده نمیشود؛ اما image پرود بر پایه `php:8.2-fpm-alpine` ساخته میشود و در `Dockerfile` فقط این افزونهها نصب میشوند:
|
||||
|
||||
```dockerfile
|
||||
docker-php-ext-install pdo_mysql intl opcache
|
||||
```
|
||||
|
||||
`soap` نصب نمیشود، بنابراین در پرود هنگام initiate کردن پرداخت، fatal میشود:
|
||||
|
||||
```
|
||||
Payment initiate failed (mellat): Class "SoapClient" not found @ /app/src/Payment/Gateway/MellatGateway.php:70
|
||||
context {"orderId":"6","amount":150000}
|
||||
```
|
||||
|
||||
## مشکل / هدف
|
||||
|
||||
افزونه `ext-soap` روی image پرود نصب شود تا مسیر prod درگاه ملت (`bpPayRequest` / `bpVerifyRequest` / `bpSettleRequest` / `bpRefundRequest` / `bpReversalRequest`) روی `SoapClient` کار کند.
|
||||
|
||||
نکته مهم: sandbox این مشکل را ندارد چون مسیر sandbox از REST (JSON + Basic Auth) استفاده میکند نه SOAP. مشکل فقط در حالت prod (فلگ `mellat_sandbox` غیرفعال) رخ میدهد.
|
||||
|
||||
## فایلهای مرتبط
|
||||
|
||||
| فایل | نقش |
|
||||
|------|-----|
|
||||
| `Dockerfile` (stage 3 — runtime) | نصب افزونههای PHP؛ باید `soap` اضافه شود |
|
||||
| `src/Payment/Gateway/MellatGateway.php` | خط ۷۰: `new \SoapClient($this->wsdlUrl(), ...)` — نیازمند `ext-soap` |
|
||||
| `composer.json` | افزودن `ext-soap` به `require` تا نبود افزونه زودتر (build-time) شناسایی شود |
|
||||
|
||||
## وضعیت فعلی
|
||||
|
||||
`Dockerfile` — بلوک نصب افزونهها در stage runtime (خطوط ~62–73):
|
||||
|
||||
```dockerfile
|
||||
RUN set -eu; \
|
||||
export MAKEFLAGS="-j$(nproc)"; \
|
||||
retry() { for i in 1 2 3 4 5; do "$@" && return 0; echo "retry $i: $*"; sleep 5; done; return 1; }; \
|
||||
retry apk add --no-cache nginx supervisor icu-libs \
|
||||
&& retry apk add --no-cache --virtual .build-deps $PHPIZE_DEPS icu-dev \
|
||||
&& docker-php-ext-install pdo_mysql intl opcache \
|
||||
&& retry curl -sSLf "https://github.com/phpredis/phpredis/archive/refs/tags/${PHPREDIS_VERSION}.tar.gz" -o /tmp/phpredis.tar.gz \
|
||||
&& mkdir -p /usr/src/php/ext/redis \
|
||||
&& tar -xf /tmp/phpredis.tar.gz -C /usr/src/php/ext/redis --strip-components=1 \
|
||||
&& docker-php-ext-install redis \
|
||||
&& rm -rf /tmp/phpredis.tar.gz \
|
||||
&& apk del .build-deps
|
||||
```
|
||||
|
||||
`MellatGateway.php:67-78`:
|
||||
|
||||
```php
|
||||
private function soap(): \SoapClient
|
||||
{
|
||||
if ($this->soap === null) {
|
||||
$this->soap = new \SoapClient($this->wsdlUrl(), [
|
||||
'trace' => true,
|
||||
'exceptions' => true,
|
||||
'encoding' => 'UTF-8',
|
||||
'connection_timeout' => 10,
|
||||
]);
|
||||
}
|
||||
return $this->soap;
|
||||
}
|
||||
```
|
||||
|
||||
## وظایف
|
||||
|
||||
### ۱. افزودن `soap` به `docker-php-ext-install` در `Dockerfile`
|
||||
|
||||
افزونهٔ `soap` جزو افزونههای bundled خودِ PHP است و نیاز به شبکه (pecl/github) ندارد؛ فقط برای کامپایل به هدرهای `libxml2-dev` نیاز دارد. `libxml2-dev` را به `.build-deps` اضافه کن (تا بعد از build با `apk del .build-deps` پاک شود) و `soap` را به لیست `docker-php-ext-install` اضافه کن.
|
||||
|
||||
نتیجهٔ مطلوب:
|
||||
|
||||
```dockerfile
|
||||
&& retry apk add --no-cache --virtual .build-deps $PHPIZE_DEPS icu-dev libxml2-dev \
|
||||
&& docker-php-ext-install pdo_mysql intl opcache soap \
|
||||
```
|
||||
|
||||
نکته: `libxml2` (کتابخانهٔ runtime، بدون `-dev`) در image پایهٔ PHP موجود است، پس افزونهٔ کامپایلشده در runtime بدون مشکل load میشود و نیازی به افزودن آن به لیست runtime نیست. فقط هدرهای `-dev` که در build لازماند در `.build-deps` قرار میگیرند.
|
||||
|
||||
### ۲. اعلام نیازمندی در `composer.json`
|
||||
|
||||
`ext-soap` را به بخش `require` اضافه کن تا اگر روی محیطی افزونه نبود، در زمان `composer install` هشدار/خطا داده شود و مشکل زودتر از runtime دیده شود:
|
||||
|
||||
```jsonc
|
||||
"require": {
|
||||
// ... موجود
|
||||
"ext-soap": "*"
|
||||
}
|
||||
```
|
||||
|
||||
توجه: در `Dockerfile` مرحلهٔ vendor از `--ignore-platform-reqs` استفاده میکند، پس این افزوده build را نمیشکند؛ صرفاً بهعنوان مستندسازی نیازمندی و اعتبارسنجی در محیطهای دیگر عمل میکند.
|
||||
|
||||
### ۳. تأیید و rebuild
|
||||
|
||||
بعد از تغییر `Dockerfile`، image پرود باید دوباره build/deploy شود (Coolify). برای تأیید نصب افزونه پس از build:
|
||||
|
||||
```bash
|
||||
php -m | grep -i soap # باید soap را چاپ کند
|
||||
php -r 'var_dump(class_exists("SoapClient"));' # bool(true)
|
||||
```
|
||||
|
||||
## نکات مهم
|
||||
|
||||
- مشکل صرفاً محیطی (نبود افزونه در image پرود) است، نه باگ منطقی در کد `MellatGateway`. کد درست است؛ فقط وابستگی runtime روی پرود غایب بود.
|
||||
- بعد از deploy، پرداخت واقعی ملت (حالت prod، فلگ `mellat_sandbox=0`) باید یکبار تست شود تا مسیر SOAP (`bpPayRequest`) واقعاً پاسخ بگیرد.
|
||||
- الگوی موجود در `Dockerfile` را رعایت کن: build-deps مجازی که بعد از کامپایل با `apk del .build-deps` حذف میشوند تا حجم image کم بماند. `libxml2-dev` را داخل همین گروه بگذار، نه بهصورت دائمی.
|
||||
- این تغییر API را عوض نمیکند؛ نیازی به بهروزرسانی `docs/api/payment.md` نیست (فقط اگر رفتار/قرارداد endpoint تغییر کند لازم میشد).
|
||||
+2
-2
@@ -63,8 +63,8 @@ RUN set -eu; \
|
||||
export MAKEFLAGS="-j$(nproc)"; \
|
||||
retry() { for i in 1 2 3 4 5; do "$@" && return 0; echo "retry $i: $*"; sleep 5; done; return 1; }; \
|
||||
retry apk add --no-cache nginx supervisor icu-libs \
|
||||
&& retry apk add --no-cache --virtual .build-deps $PHPIZE_DEPS icu-dev \
|
||||
&& docker-php-ext-install pdo_mysql intl opcache \
|
||||
&& retry apk add --no-cache --virtual .build-deps $PHPIZE_DEPS icu-dev libxml2-dev \
|
||||
&& docker-php-ext-install pdo_mysql intl opcache soap \
|
||||
&& retry curl -sSLf "https://github.com/phpredis/phpredis/archive/refs/tags/${PHPREDIS_VERSION}.tar.gz" -o /tmp/phpredis.tar.gz \
|
||||
&& mkdir -p /usr/src/php/ext/redis \
|
||||
&& tar -xf /tmp/phpredis.tar.gz -C /usr/src/php/ext/redis --strip-components=1 \
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"php": ">=8.2",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-soap": "*",
|
||||
"doctrine/doctrine-bundle": ">=2.18.3",
|
||||
"doctrine/doctrine-migrations-bundle": "*",
|
||||
"doctrine/orm": "^3.6",
|
||||
|
||||
Reference in New Issue
Block a user