You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony 6+EasyAdmin自定义Canvas签名表单字段配置求助

Symfony 6 + EasyAdmin 自定义Canvas签名字段渲染失败解决

需求

为signatureClient字段生成<canvas>标签,实现电子签名功能,替代默认的textarea。

已实现操作

  1. 创建SignatureField类(EasyAdmin自定义字段)
<?php

namespace App\EasyAdmin;

use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use App\Form\CanvasType;

class SignatureField implements FieldInterface
{
    use FieldTrait;

    public static function new(string $propertyName, ?string $label = null)
    {
        return (new self())
            ->setProperty($propertyName)
            ->setLabel($label)
            ->setFormType(CanvasType::class)
            ;
    }
}
  1. 在Crud控制器中调用字段
SignatureField::new('signatureClient')
  1. 创建CanvasType表单类型
<?php

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;

class CanvasType extends AbstractType
{
    public function getParent(): ?string
    {
        return TextareaType::class;
    }

    public function getBlockPrefix(): string
    {
        return 'canvas';
    }
}
  1. 编写自定义Twig模板
{# templates/admin/form/custom_types.html.twig #}

{% form_theme form 'form.html.twig' %}
{% block _InterventionTechnique_signatureClient_widget %}

    <canvas id="{{ field.name}}" width="300" height="100">{{ field.value}}</canvas> 
{% endblock %}

当前问题

表单仍渲染为textarea标签,自定义Twig模板未生效:

<textarea id="InterventionTechnique_signatureClient" name="InterventionTechnique[signatureClient]" class="form-control"></textarea>

解决方案

1. 修正Twig模板的块命名与结构

自定义表单类型的Twig块需与getBlockPrefix()返回值对应(即canvas_widget),而非针对特定字段的硬编码块名。同时需保留隐藏的textarea用于存储签名数据(提交表单时需要将canvas内容转为字符串存入此字段)。

新建templates/form/canvas_widget.html.twig:

{% block canvas_widget %}
    {# 隐藏原始textarea,用于存储签名的Base64数据 #}
    <textarea {{ block('widget_attributes') }} style="display: none;">{{ value }}</textarea>
    {# 渲染可交互的canvas #}
    <canvas id="{{ id }}" width="{{ width }}" height="{{ height }}" style="border: 1px solid #ddd;"></canvas>
{% endblock %}

2. 完善CanvasType类,传递配置参数

添加buildView和configureOptions方法,将宽高等配置传递到模板,并支持自定义参数:

<?php

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\OptionsResolver\OptionsResolver;

class CanvasType extends AbstractType
{
    public function buildView(FormView $view, FormInterface $form, array $options): void
    {
        // 将配置参数传递到模板
        $view->vars['width'] = $options['width'];
        $view->vars['height'] = $options['height'];
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'width' => 300,
            'height' => 100,
            'mapped' => true, // 确保字段与实体属性绑定
        ]);
    }

    public function getParent(): ?string
    {
        return TextareaType::class;
    }

    public function getBlockPrefix(): string
    {
        return 'canvas';
    }
}

3. 在EasyAdmin中配置表单主题

需要让EasyAdmin加载自定义的表单模板,可在Dashboard或Crud控制器中配置:

use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;

class DashboardController extends AbstractDashboardController
{
    public function configureDashboard(): Dashboard
    {
        return Dashboard::new()
            // 其他配置...
            ->setFormThemes(['form/canvas_widget.html.twig', '@EasyAdmin/crud/form_theme.html.twig']);
    }

    // 或者针对单个Crud配置
    public function configureCrud(): Crud
    {
        return Crud::new()
            ->setFormThemes(['form/canvas_widget.html.twig', '@EasyAdmin/crud/form_theme.html.twig']);
    }
}

4. 优化SignatureField,支持自定义宽高

为字段添加链式方法,方便在Crud中快速调整canvas尺寸:

<?php

namespace App\EasyAdmin;

use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use App\Form\CanvasType;

class SignatureField implements FieldInterface
{
    use FieldTrait;

    public static function new(string $propertyName, ?string $label = null)
    {
        return (new self())
            ->setProperty($propertyName)
            ->setLabel($label)
            ->setFormType(CanvasType::class)
            ->setFormTypeOptions([
                'width' => 300,
                'height' => 100,
            ]);
    }

    public function setWidth(int $width): self
    {
        $this->setFormTypeOption('width', $width);
        return $this;
    }

    public function setHeight(int $height): self
    {
        $this->setFormTypeOption('height', $height);
        return $this;
    }
}

5. 补充前端签名逻辑(可选)

需要添加JavaScript实现canvas的签名绘制功能,示例:

document.addEventListener('DOMContentLoaded', function() {
    const canvas = document.getElementById('InterventionTechnique_signatureClient');
    const textarea = document.querySelector('textarea[name="InterventionTechnique[signatureClient]"]');
    if (!canvas) return;

    const ctx = canvas.getContext('2d');
    let isDrawing = false;

    // 绘制逻辑
    canvas.addEventListener('mousedown', startDrawing);
    canvas.addEventListener('mousemove', draw);
    canvas.addEventListener('mouseup', stopDrawing);
    canvas.addEventListener('mouseout', stopDrawing);

    function startDrawing(e) {
        isDrawing = true;
        ctx.beginPath();
        ctx.moveTo(e.offsetX, e.offsetY);
    }

    function draw(e) {
        if (!isDrawing) return;
        ctx.lineTo(e.offsetX, e.offsetY);
        ctx.stroke();
    }

    function stopDrawing() {
        isDrawing = false;
        // 将canvas内容转为Base64存入textarea
        textarea.value = canvas.toDataURL();
    }
});

问题根源

  1. 原模板使用了针对特定字段的硬编码块名_InterventionTechnique_signatureClient_widget,未匹配自定义表单类型的canvas前缀,导致Twig无法识别并替换。
  2. 未在EasyAdmin中配置加载自定义表单主题,自定义模板未被纳入渲染流程。
  3. 未保留隐藏的textarea字段,无法将canvas的签名数据提交到后端。

内容的提问来源于stack exchange,提问作者user2565112

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 04:14:50