laulamanapps/document-signer-symfony
Composer 安装命令:
composer require laulamanapps/document-signer-symfony
包简介
Symfony bundle for the document signer SDK: configuration, a driver manager, and verified webhook routes for ValidSign and DocuSign.
README 文档
README
A Symfony bundle around the Document Signer SDK: configuration, a driver manager, and verified webhook routes for ValidSign and DocuSign. It mirrors the Laravel package — same providers-list config, same webhook event.
Contents
- Install
- Configure
- Sending an envelope
- Recipient override (dev / staging)
- PDF renderer
- Webhooks
- Custom providers
- Requirements
Install
composer require laulamanapps/document-signer-symfony
Add at least one provider package (both are optional):
composer require laulamanapps/document-signer-validsign # for the validsign provider composer require laulamanapps/document-signer-docusign # for the docusign provider composer require spatie/browsershot # default PDF renderer
Register the bundle (Symfony Flex does this automatically):
// config/bundles.php return [ // ... LauLamanApps\DocumentSigner\Symfony\DocumentSignerBundle::class => ['all' => true], ];
Configure
# config/packages/document_signer.yaml document_signer: # Provider NAME to use when none is given. Omit to auto-select the sole # configured provider; required when more than one is configured. default: '%env(default::DOCUMENT_SIGNER_DRIVER)%' providers: - class: 'LauLamanApps\DocumentSigner\ValidSign\ValidSignProvider' config: api_key: '%env(VALIDSIGN_API_KEY)%' base_url: '%env(default:https://my.validsign.nl/api:VALIDSIGN_BASE_URL)%' webhook: callback_secret: '%env(VALIDSIGN_CALLBACK_SECRET)%' - class: 'LauLamanApps\DocumentSigner\DocuSign\DocuSignProvider' config: integration_key: '%env(DOCUSIGN_INTEGRATION_KEY)%' user_id: '%env(DOCUSIGN_USER_ID)%' account_id: '%env(DOCUSIGN_ACCOUNT_ID)%' private_key_path: '%env(DOCUSIGN_PRIVATE_KEY_PATH)%' webhook: hmac_secret: '%env(DOCUSIGN_CONNECT_HMAC_SECRET)%'
Each entry co-locates the provider class, its config, and its webhook
secret. A provider's short name — used by default and the webhook URL — is
the NAME constant on its class (validsign, docusign).
Sending an envelope
Type-hint the manager:
use LauLamanApps\DocumentSigner\Symfony\DocumentSignerManager; use LauLamanApps\DocumentSigner\Sdk\Document\Document; use LauLamanApps\DocumentSigner\Sdk\Envelope\Envelope; use LauLamanApps\DocumentSigner\Sdk\Signer\Signer; public function __construct(private DocumentSignerManager $signer) {} public function send(): void { $receipt = $this->signer->send(new Envelope( name: 'NDA', documents: [new Document(id: 'nda', name: 'NDA', html: '<p>{[signature:party:sig]}</p>')], signers: [new Signer(key: 'party', name: 'Jane Doe', email: 'jane@example.com')], emailSubject: 'Please sign the NDA', )); // Switch provider at runtime: $this->signer->driver('docusign')->getStatus($receipt->providerEnvelopeId); }
Recipient override (dev / staging)
Seeded and development data is full of reserved domains — example.com,
*.test, and friends — that providers like ValidSign reject outright, so an
otherwise-valid envelope fails the moment you try to send it. The recipient
override rewrites every signer's email before the envelope reaches the
provider, redirecting those addresses to a real inbox you control instead.
It is off by default and adds zero overhead when disabled — the real provider
is used directly, no wrapper installed. Keep it off in production (bind it
to your environment, e.g. only in config/packages/dev/).
# config/packages/dev/document_signer.yaml document_signer: recipient_override: enabled: true to: 'you@yourdomain.test'
That's the whole setup for the default (catch_all) strategy. It applies on
every send path — $manager->send(), $manager->driver('validsign')->send(),
and a manually resolved instance alike.
Strategy
strategy chooses how each address is rewritten. Given to: dev@you.test
(or domain: you.test):
| Strategy | alice@example.com becomes |
Notes |
|---|---|---|
catch_all (default) |
dev+alice=example.com@you.test |
Everyone lands in one inbox, but the original address is folded into a +tag so each signer stays a distinct recipient. ValidSign rejects duplicate recipients on one package, so this is the safe default for multi-signer envelopes. Requires to. |
domain |
alice@you.test |
Keeps the local part, swaps only the domain. Recipients stay unique; you need a catch-all inbox on that domain to actually receive the mail. Requires domain. |
redirect |
dev@you.test |
Sends everyone to to verbatim. Simplest, but multiple signers on one envelope collapse to the same address (a provider may reject that) — use for single-signer flows only. Requires to. |
A misconfigured-but-enabled override (e.g. catch_all with no to) throws a
clear InvalidArgumentException on the first send, rather than silently
misrouting mail.
Scope
By default (only_domains empty) every signer address is rewritten once
the override is enabled — the enabled flag is the only guard, so keep it off
in production. Add entries only to narrow the rewrite to specific domains and
let all others pass through untouched:
document_signer: recipient_override: enabled: true strategy: domain domain: 'you.test' only_domains: # rewrite only seeded/test data, leave the rest - 'example.com' - '*.test' - '*.local'
Entries match case-insensitively; a *. prefix does a suffix match (*.test
matches foo.test).
PDF renderer
The manager wires the SDK's BrowsershotPdfRenderer into every provider by
default. To use a different engine, register your own PdfRenderer service and
alias the interface to it — the bundle only sets the default alias if you
haven't:
services: LauLamanApps\DocumentSigner\Sdk\Pdf\PdfRenderer: alias: App\Pdf\GotenbergRenderer
Webhooks
Import the bundle's webhook route with the prefix you want:
# config/routes/document_signer.yaml document_signer: resource: '@DocumentSignerBundle/config/routes.php' prefix: /document-signer/webhooks
That exposes POST /document-signer/webhooks/{provider}. The endpoint verifies
the shared-secret signature (set the webhook secret to enable it) and
dispatches a DocumentSignerWebhookReceived event; unverified requests get a
401. Listen for it:
use LauLamanApps\DocumentSigner\Symfony\Event\DocumentSignerWebhookReceived; use LauLamanApps\DocumentSigner\ValidSign\ValidSignProvider; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; #[AsEventListener] final class HandleSignerWebhook { public function __invoke(DocumentSignerWebhookReceived $event): void { // Originating provider is always present, even when $event->event is null: if ($event->provider === ValidSignProvider::class) { /* ... */ } match (true) { $event->event?->isCompleted() => $this->onCompleted($event->payload), $event->event?->isDeclined() => $this->onDeclined($event->payload), default => null, }; } }
$event->event is a WebhookEvent enum (or null for a provider without one).
Its short name is $event->provider::NAME, and the raw body is on
$event->payload / $event->request.
Translated labels
use LauLamanApps\DocumentSigner\Symfony\Translation\EventTranslator; public function __invoke(DocumentSignerWebhookReceived $event, EventTranslator $labels): void { if ($event->event !== null) { // "Package complete" (en), "Pakket voltooid" (nl) $label = $labels->label($event->event, $event->provider); } }
The bundle ships English and Dutch labels under the document-signer
translation domain (translations/document-signer.{en,nl}.php).
Custom providers
Any SignatureProvider works. Register it as a service (it's autoconfigured
with the document_signer.provider tag), and add a providers entry pointing
at its class:
document_signer: providers: - class: 'App\Signing\AcmeSignProvider' webhook: secret: '%env(ACME_WEBHOOK_SECRET)%'
- Declare a
public const string NAMEon the provider — its short name. - Wire the provider's own dependencies (credentials, the
PdfRenderer) through normal Symfony service config. - Implement
Webhook\ProvidesWebhookto get an auto-verified webhook route.
Requirements
- PHP 8.5
- Symfony 6.4, 7.x or 8.x
laulamanapps/document-signer-sdk^2.0laulamanapps/document-signer-validsignor-docusign(each optional)- Node.js + Puppeteer (for the default Browsershot renderer)
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 3
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: proprietary
- 更新时间: 2026-07-07