承接 laulamanapps/document-signer-symfony 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

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

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 NAME on the provider — its short name.
  • Wire the provider's own dependencies (credentials, the PdfRenderer) through normal Symfony service config.
  • Implement Webhook\ProvidesWebhook to get an auto-verified webhook route.

Requirements

  • PHP 8.5
  • Symfony 6.4, 7.x or 8.x
  • laulamanapps/document-signer-sdk ^2.0
  • laulamanapps/document-signer-validsign or -docusign (each optional)
  • Node.js + Puppeteer (for the default Browsershot renderer)

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 3
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: proprietary
  • 更新时间: 2026-07-07

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固