formpanel/formpanel-laravel 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

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

formpanel/formpanel-laravel

最新稳定版本:1.0.0

Composer 安装命令:

composer require formpanel/formpanel-laravel

包简介

Laravel integration for the FormPanel PHP client library

README 文档

README

Laravel integration for the FormPanel PHP client library. This package provides a seamless way to submit forms to FormPanel API from your Laravel applications with configuration, facades, and artisan commands.

Requirements

  • PHP 8.2 or higher
  • Laravel 11.x or 12.x
  • Composer

Installation

Install the package via Composer:

composer require formpanel/formpanel-laravel

The service provider will be automatically registered via Laravel's package auto-discovery.

Configuration

Publish Configuration

Publish the configuration file:

php artisan vendor:publish --tag=formpanel-config

This will create a config/formpanel.php file in your application.

Environment Variables

Add the following to your .env file:

FORMPANEL_API_KEY=your-api-key-here
FORMPANEL_FORM_SLUG=contact-form

Required:

  • FORMPANEL_API_KEY - Your FormPanel API key

Optional:

  • FORMPANEL_FORM_SLUG - Default form slug
  • FORMPANEL_BASE_URL - Base URL (default: https://api.formpanel.io/api/v1)
  • FORMPANEL_TIMEOUT - Request timeout in seconds (default: 30)
  • FORMPANEL_MAX_RETRIES - Maximum retry attempts (default: 3)
  • FORMPANEL_LOGGING - Enable debug logging (default: false)

Usage

Using the Facade

The package provides a convenient facade for accessing the FormPanel client:

use Formpanel\Laravel\Facades\Formpanel;

// Submit form data using the default form slug from config
$result = Formpanel::submit([
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'message' => 'Hello from Laravel!',
]);

echo "Submission ID: " . $result->id;

Using a Specific Form

Create a client for a specific form using the form() method:

use Formpanel\Laravel\Facades\Formpanel;

// Get a client for a specific form
$client = Formpanel::form('contact-form');

// Submit data
$result = $client->submit([
    'name' => 'Jane Doe',
    'email' => 'jane@example.com',
    'message' => 'Hello!',
]);

// Get form information
$form = $client->get();
echo "Form: {$form->name}";
echo "Fields: " . count($form->fields);

Using Dependency Injection

Inject the client into your controllers, jobs, or services:

use Formpanel\FormClient;

class ContactController extends Controller
{
    public function __construct(protected FormClient $formpanel)
    {
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string',
            'email' => 'required|email',
            'message' => 'required|string',
        ]);

        try {
            $result = $this->formpanel->submit($validated);

            return redirect()->back()->with('success', 'Form submitted successfully!');
        } catch (\Formpanel\Exceptions\ValidationException $e) {
            return redirect()->back()->withErrors($e->getErrors());
        }
    }
}

Using the Factory for Multiple Forms

Use the factory to create clients for different forms:

use Formpanel\Laravel\FormpanelFactory;

class FormController extends Controller
{
    public function __construct(protected FormpanelFactory $formpanel)
    {
    }

    public function submitContact(Request $request)
    {
        $client = $this->formpanel->make('contact-form');
        $result = $client->submit($request->validated());

        return redirect()->back()->with('success', 'Contact form submitted!');
    }

    public function submitNewsletter(Request $request)
    {
        $client = $this->formpanel->make('newsletter-signup');
        $result = $client->submit(['email' => $request->email]);

        return redirect()->back()->with('success', 'Subscribed to newsletter!');
    }
}

Getting Form Information

Retrieve form details including field definitions:

use Formpanel\Laravel\Facades\Formpanel;

$form = Formpanel::get();

echo "Form: {$form->name}\n";
echo "Status: {$form->status}\n";
echo "Description: {$form->description}\n";

foreach ($form->fields as $field) {
    echo "- {$field->name} ({$field->type})";
    echo $field->required ? " [required]" : "";
    echo "\n";
}

Controller Example

Complete controller example with error handling:

<?php

namespace App\Http\Controllers;

use Formpanel\FormClient;
use Formpanel\Exceptions\ValidationException;
use Formpanel\Exceptions\FormpanelException;
use Illuminate\Http\Request;

class ContactController extends Controller
{
    public function __construct(protected FormClient $formpanel)
    {
    }

    public function create()
    {
        return view('contact');
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|email',
            'subject' => 'required|string|max:255',
            'message' => 'required|string',
        ]);

        try {
            $result = $this->formpanel->submit($validated);

            return redirect()
                ->route('contact.thank-you')
                ->with('submission_id', $result->id);

        } catch (ValidationException $e) {
            // FormPanel validation failed
            return redirect()
                ->back()
                ->withInput()
                ->withErrors($e->getErrors());

        } catch (FormpanelException $e) {
            // Other FormPanel errors
            return redirect()
                ->back()
                ->withInput()
                ->with('error', 'Failed to submit form: ' . $e->getMessage());
        }
    }
}

Queue Integration

Submit forms asynchronously using Laravel queues:

<?php

namespace App\Jobs;

use Formpanel\Laravel\FormpanelFactory;
use Formpanel\Exceptions\FormpanelException;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

class SubmitFormToFormpanel implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(
        protected string $formSlug,
        protected array $data
    ) {
    }

    public function handle(FormpanelFactory $factory): void
    {
        try {
            $client = $factory->make($this->formSlug);
            $result = $client->submit($this->data);

            Log::info('Form submitted to FormPanel', [
                'submission_id' => $result->id,
                'form_slug' => $this->formSlug,
            ]);
        } catch (FormpanelException $e) {
            Log::error('Failed to submit form to FormPanel', [
                'error' => $e->getMessage(),
                'form_slug' => $this->formSlug,
            ]);

            throw $e;
        }
    }
}

Dispatch the job:

use App\Jobs\SubmitFormToFormpanel;

SubmitFormToFormpanel::dispatch('contact-form', [
    'name' => 'John Doe',
    'email' => 'john@example.com',
]);

Artisan Commands

Test API Connection

Test your FormPanel API integration:

php artisan formpanel:test contact-form \
    --field=name="John Doe" \
    --field=email="john@example.com" \
    --field=message="Test message"

Output:

Testing FormPanel API integration...

Form: contact-form
Data:
  name: John Doe
  email: john@example.com
  message: Test message

Form submitted successfully!

Response:
  Submission ID: 550e8400-e29b-41d4-a716-446655440000
  Message: Form submitted successfully!

Error Handling

The package uses the same exception classes as the base PHP library:

use Formpanel\Laravel\Facades\Formpanel;
use Formpanel\Exceptions\AuthenticationException;
use Formpanel\Exceptions\ValidationException;
use Formpanel\Exceptions\NotFoundException;
use Formpanel\Exceptions\RateLimitException;
use Formpanel\Exceptions\FormpanelException;

try {
    $result = Formpanel::submit($data);

} catch (AuthenticationException $e) {
    // Invalid API key (401)
    Log::error('FormPanel authentication failed', ['error' => $e->getMessage()]);

} catch (NotFoundException $e) {
    // Form not found (404)
    Log::warning('FormPanel form not found', ['error' => $e->getMessage()]);

} catch (ValidationException $e) {
    // Validation errors (422)
    $errors = $e->getErrors();
    return back()->withErrors($errors);

} catch (RateLimitException $e) {
    // Rate limit exceeded (429)
    $retryAfter = $e->getRetryAfter();
    Log::warning('FormPanel rate limit exceeded', ['retry_after' => $retryAfter]);

} catch (FormpanelException $e) {
    // Other errors (network issues, parsing errors, etc.)
    Log::error('FormPanel error', ['error' => $e->getMessage()]);
}

Response Objects

SubmissionResult

Returned by submit():

$result = Formpanel::submit($data);

$result->id;       // string - Submission UUID
$result->success;  // bool - Whether submission was successful
$result->message;  // string - Success/error message

Form

Returned by get():

$form = Formpanel::get();

$form->id;          // string - Form UUID
$form->name;        // string - Form name
$form->slug;        // string - Form slug
$form->description; // ?string - Form description
$form->status;      // string - Form status (e.g., 'active')
$form->fields;      // FormField[] - Array of field definitions
$form->createdAt;   // DateTimeImmutable
$form->updatedAt;   // DateTimeImmutable

FormField

foreach ($form->fields as $field) {
    $field->name;        // string - Field name/identifier
    $field->label;       // string - Display label
    $field->type;        // string - Field type
    $field->required;    // bool - Whether field is required
    $field->placeholder; // ?string - Placeholder text
    $field->helpText;    // ?string - Help text
    $field->config;      // array - Additional configuration
}

Advanced Configuration

Custom Retry Configuration

Configure retry behavior in your .env:

FORMPANEL_MAX_RETRIES=5
FORMPANEL_RETRY_BASE_DELAY=500
FORMPANEL_RETRY_MAX_DELAY=60000
FORMPANEL_RETRY_MULTIPLIER=2.0

Or in config/formpanel.php:

'retry' => [
    'max_retries' => 5,
    'base_delay_ms' => 500,
    'max_delay_ms' => 60000,
    'multiplier' => 2.0,
],

Logging

Enable request/response logging for debugging:

FORMPANEL_LOGGING=true
FORMPANEL_LOG_CHANNEL=stack

When enabled, the package will use Laravel's logging system with PSR-3 compatibility.

Testing

Mock in Tests

Use Laravel's service container to mock the client in tests:

use Formpanel\FormClient;
use Formpanel\SubmissionResult;
use Mockery;

public function test_contact_form_submission()
{
    $mockClient = Mockery::mock(FormClient::class);
    $mockClient->shouldReceive('submit')
        ->once()
        ->with(Mockery::any())
        ->andReturn(new SubmissionResult(
            id: '550e8400-e29b-41d4-a716-446655440000',
            success: true,
            message: 'Form submitted successfully!',
        ));

    $this->app->instance(FormClient::class, $mockClient);

    $response = $this->post('/contact', [
        'name' => 'John Doe',
        'email' => 'john@example.com',
        'message' => 'Test message',
    ]);

    $response->assertRedirect();
}

Using Custom HTTP Client

For integration testing, you can inject a custom HTTP client:

use Formpanel\FormClient;
use Formpanel\Http\HttpClientInterface;

$mockHttpClient = new class implements HttpClientInterface {
    public function get(string $uri): array {
        return ['id' => 'test', 'name' => 'Test Form', /* ... */];
    }

    public function post(string $uri, array $data): array {
        return ['submission_id' => 'test-123', 'success' => true, 'message' => 'OK'];
    }
};

$client = new FormClient(
    apiKey: 'test-key',
    formSlug: 'test-form',
    httpClient: $mockHttpClient,
);

Run Package Tests

composer install
./vendor/bin/phpunit

Security

  • Store API keys in .env file, never in code
  • Use Laravel's validation before submitting to FormPanel
  • Enable HTTPS in production
  • The client includes automatic retry with exponential backoff for transient errors

Support

License

MIT License. See LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

统计信息

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

GitHub 信息

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

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-11-25