symfony - 如何在 symfony 中为奏鸣曲块服务添加中继器(克隆)字段
问题描述
我正在使用 CMS 选项处理 symfony(4.2) 项目。所以我决定使用 Sonata bundles 来实现类似 WP 的 CMS。目前我已经安装并使用了 SonataAdminBundle、SonataMediaBundle、SonataBlockBundle...等。我还为页面块创建了带有基本表单字段的自定义服务,它对我来说很好用。现在我想创建一个带有重复字段的表单,如克隆系统
我创建了一个名为 CloneType 的新表单类型并自定义了表单模板。还在块服务文件中添加了 CloneType 字段,现在表单如下图所示
https://i.stack.imgur.com/WmYFg.png
在浏览器中检查时,我的输入看起来像这样
<input type="text" id="s9fdc9db89c_settings_cxi_different_title" name="s9fdc9db89c[settings][cxi_different][title_1]" class=" form-control" value="test">
<input type="text" id="s9fdc9db89c_settings_cxi_different_title" name="s9fdc9db89c[settings][cxi_different][title_2]" class=" form-control" value="test">
src/Form/Type/CloneType.php
<?php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CloneType extends AbstractType
{
public function getParent()
{
return FormType::class;
}
}
模板/sonataadmin/forms/clone.twig.html
{% block clone_widget %}
{% spaceless %}
<div class="clone-wrapper">
<div id="clonedInput1" class="clonedInput">
{{- form_widget(form) -}}
{{- form_errors(form) -}}
<div class="actions">
<a class="btn btn-info clone">Clone</a>
<a class="btn btn-warning remove">Remove</a>
</div>
</div>
</div>
{% endspaceless %}
{% block javascripts %}
<script type="text/javascript">
var regex = /^(.+?)(\d+)$/i;
var cloneIndex = $(".clonedInput").length;
function clone(){
$(this).parents(".clonedInput").clone()
.appendTo("clone-wrapper")
.attr("id", "clonedInput" + cloneIndex)
.find("*")
.each(function() {
var id = this.id || "";
var match = id.match(regex) || [];
if (match.length == 3) {
this.id = match[1] + (cloneIndex);
}
})
.on('click', 'a.clone', clone)
.on('click', 'a.remove', remove);
cloneIndex++;
}
function remove(){
$(this).parents(".clonedInput").remove();
}
$("a.clone").on("click", clone);
$("a.remove").on("click", remove);
</script>
{% endblock %}
{% endblock %}
src/Application/Sonata/BlockBundle/Block/CxiDifferentBlockService.php
<?php
namespace App\Application\Sonata\BlockBundle\Block;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Sonata\Form\Type\ImmutableArrayType;
use Sonata\Form\Validator\ErrorElement;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\BlockBundle\Meta\Metadata;
use Sonata\BlockBundle\Block\BlockContextInterface;
use Sonata\BlockBundle\Model\BlockInterface;
use Sonata\BlockBundle\Block\Service\AbstractBlockService;
use App\Application\Sonata\PageBundle\Entity\Block;
use App\Form\Type\CloneType;
use Sonata\AdminBundle\Admin\AdminInterface;
class CxiDifferentBlockService extends AbstractBlockService
{
public function buildEditForm(FormMapper $formMapper, BlockInterface $block)
{
$formMapper
->add('settings', ImmutableArrayType::class, [
'keys' => [
['title', TextType::class, [
'label' => 'Title (H2)',
'required' => false,
]],
[$this->getCloneBuilder($formMapper), null, []],
],
])
;
}
protected function getCloneBuilder(FormMapper $formMapper)
{
return $formMapper->create('cxi_different', CloneType::class, ['required' => false,'by_reference' => false,'allow_extra_fields'=>true])
->add('title', TextType::class,['required' => false, 'allow_extra_fields'=>true, 'by_reference' => false])
;
}
}
我想更新数据库中的克隆字段值。但它不起作用。我在提交表单时检查了数据。奏鸣曲形式未在 post 数组中添加克隆字段。帖子数组看起来像下面的实际结果
实际结果 :
Array(
[title] => test
[cxi_different] => Array
(
[title_1] => test
)
)
预期结果 :
Array(
[title] => test
[cxi_different] => Array
(
[title_1] => test
[title_2] => test
)
)
提前致谢!
解决方案
我已经使用CollectionType来实现这一点,并且我已经按照以下步骤来实现这一点
第 1 步: 我在 src/Form/CloneFormType.php 中添加了新的 FormType
<?php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Sonata\AdminBundle\Form\Type\CollectionType;
final class CloneFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('title_1', TextType::class)
->add('title_2', TextType::class)
;
}
}
第 2 步: 现在 BlockService 应该是这样的
<?php
namespace App\Application\Sonata\BlockBundle\Block;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Sonata\Form\Type\ImmutableArrayType;
use Sonata\Form\Validator\ErrorElement;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\BlockBundle\Meta\Metadata;
use Sonata\BlockBundle\Block\BlockContextInterface;
use Sonata\BlockBundle\Model\BlockInterface;
use Sonata\BlockBundle\Block\Service\AbstractBlockService;
use App\Application\Sonata\PageBundle\Entity\Block;
use App\Form\CloneFormType;
use Sonata\AdminBundle\Admin\AdminInterface;
class CxiDifferentBlockService extends AbstractBlockService
{
public function buildEditForm(FormMapper $formMapper, BlockInterface $block)
{
$formMapper
->add('settings', ImmutableArrayType::class, [
'keys' => [
['title', TextType::class, [
'label' => 'Title (H2)',
'required' => false,
]],
['cxi_different', CollectionType::class, [
'required' => false,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false,
'allow_extra_fields' => true,
'entry_type' => CloneFormType::class,
]],
],
])
;
}
}
第 3 步: 您可以删除以下文件。使用此CollectionType时不需要
- src/Form/Type/CloneType.php
- 模板/sonataadmin/forms/clone.twig.html
- 也不要忘记从 src/Application/Sonata/BlockBundle/Block/CxiDifferentBlockService.php 中删除这一
use App\Form\Type\CloneType;
行use App\Form\CloneFormType;
(
推荐阅读
- bootstrap-4 - 所有列 Boostrap4 的宽度相同
- python - 根据从 API Endpoint 推断的字段类型自动创建 SnowFlake 表的方法?(Python)
- mysql - 是否可以在 MySQL 中动态创建表?
- while-loop - 与while循环混淆
- html - Xpath:如何选择以下兄弟姐妹直到相似的当前节点
- azure - 请求通过多个 Azure 网络组件进行跟踪?
- opencv - 在 Raspberry Pi 4 中显示图像 OpenCV 很慢
- docker - Buildah:创建图像的工作流程
- c# - 遍历 JSON 响应 Newtonsoft.Json.Linq.JObject C#
- android - 如何将进度从根 MotionLayout 传播到包含 MotionLayout 项目的子 RecyclerView?