tudortibu / select2entity-bundle
一个将 Select2 集成为 Symfony 表单中标准实体字段的替代方案的 Symfony 扩展包。
Requires
- php: >=8.2
- doctrine/orm: >=2.4
- symfony/config: >=7.0
- symfony/dependency-injection: >=7.0
- symfony/form: >=7.0
- symfony/http-kernel: >=7.0
- symfony/property-access: >=7.0
- symfony/routing: >=7.0
- twig/twig: >=3.0
This package is not auto-updated.
Last update: 2024-10-02 10:30:58 UTC
README
简介
这是一个 Symfony 扩展包,允许使用流行的 Select2 组件作为 Symfony 表单中标准实体字段的直接替代。
需要 Symfony 7 和 PHP 8.2 或更高版本。
与标准的 Symfony 实体字段(使用 html select 渲染)相比,此扩展包提供的主要功能是列表通过远程 AJAX 调用检索。这意味着列表可以几乎无限大。唯一的限制是数据库查询或远程 Web 服务中检索数据的性能。
它适用于单选和多选。如果表单正在编辑一个 Symfony 实体,则这些模式对应于一对多和多对多关系。在多选模式下,大多数人发现 Select2 用户界面比带有 multiple=true 的标准 select 标签更容易使用,后者涉及到使用 Ctrl 键等不自然的操作。
该项目受到了 lifo/typeahead-bundle 的启发,它使用 Bootstrap 2 中的 Typeahead 组件提供类似的功能。Select2Entity 可在任何 Select2 可以安装的地方使用,包括 Bootstrap 3。
感谢 @ismailbaskin,我们现在有了 Select2 版本 4 的兼容性。
屏幕截图
这是一个带有展开的单选字段列表的表单。
这是一个带有展开的多选字段列表的表单。
安装
首先必须安装并配置 Select2。我希望设置一个演示网站,但我的设置基本上是 BraincraftedBootstrapBundle,为 Bootstrap 3 安装了 Select2。一旦 Braincrafted 扩展包开始工作,我唯一需要的文件是
从 https://github.com/select2/select2/tree/4.0.0 安装 select2.js 和 select2.css
从 https://github.com/t0m/select2-bootstrap-css/tree/bootstrap3 安装 select2-bootstrap.css。这使其适用于 Bootstrap 3。
这些文件位于我其中一个扩展包的 Resources/public/js 和 Resources/public/css 文件夹中,然后包含在我的主 layout.html.twig 文件中。
或者,可以通过以下两行代码从 CloudFlare CDN 加载 select2.js 和 select2.css 的压缩版本: https://select2.github.io。确保脚本标签位于 jQuery 加载之后。这可能是在页面页脚中。
- 将
tetranz/select2entity-bundle添加到项目composer.json的 "requires" 部分
{ // ... "require": { // ... "tetranz/select2entity-bundle": "2.*" } }
注意,这仅适用于 Select2 版本 4。如果您正在使用 Select2 版本 3.X,请在 composer.json 中使用 "tetranz/select2entity-bundle": "1.*"
- 在项目根目录中运行
php composer.phar update tetranz/select2entity-bundle - 更新项目的
config/bundles.php文件,并将此扩展包添加到 $bundles 数组中
$bundles = [ // ... Tetranz\Select2EntityBundle\TetranzSelect2EntityBundle::class => ['all' => true] ];
- 更新项目的
config/packages/twig.yaml文件,以提供全局 twig 表单模板
twig: form_themes: - '@TetranzSelect2Entity/Form/fields.html.twig' * Load the Javascript on the page. The simplest way is to add the following to your layout file. Don't forget to run console assets:install. Alternatively, do something more sophisticated with Assetic.
<script src="{{ asset('bundles/tetranzselect2entity/js/select2entity.js') }}"></script>
如何使用
以下内容适用于 Symfony 4。有关 Symfony 2/3 的配置和使用,请参阅 https://github.com/tetranz/select2entity-bundle/tree/v2.1
Select2Entity 使用简单。在表单类型类的 buildForm 方法中,将 Select2EntityType::class 指定为你原本会用 entity:class 的类型。
以下是一个示例
$builder ->add('country', Select2EntityType::class, [ 'multiple' => true, 'remote_route' => 'tetranz_test_default_countryquery', 'remote_params' => [], // static route parameters for request->query 'class' => '\Tetranz\TestBundle\Entity\Country', 'primary_key' => 'id', 'text_property' => 'name', 'minimum_input_length' => 2, 'page_limit' => 10, 'allow_clear' => true, 'delay' => 250, 'cache' => true, 'cache_timeout' => 60000, // if 'cache' is true 'language' => 'en', 'placeholder' => 'Select a country', 'query_parameters' => [ 'start' => new \DateTime(), 'end' => (new \DateTime())->modify('+5d'), // any other parameters you want your ajax route request->query to get, that you might want to modify dynamically ], // 'object_manager' => $objectManager, // inject a custom object / entity manager ])
将此代码放在包含表单类型类的文件顶部
use Tetranz\Select2EntityBundle\Form\Type\Select2EntityType;
选项
如果未设置,将使用默认值。
class是你的实体类。必需primary_key是用于唯一标识实体的属性名称。默认为 'id'text_property这是用于检索现有数据的实体属性。如果省略 text_property,则实体将被转换为字符串。这需要它有 __toString() 方法。multiple为多选(多对多)时为 true。单选(多对一)时为 false。minimum_input_length是触发搜索之前需要按下的键数。默认为 2。page_limit这作为远程调用的查询参数传递。它旨在用于限制返回列表的大小。默认为 10。scroll为 true 将启用无限滚动。默认为 false。allow_clear为 true 将导致 Select2 显示一个用于清除值的 x。默认为 false。allow_add是 Select2 的添加标签设置选项数组。仅在表单上 'multiple' 为 true 时可用。enabled启用允许新标签选项。True 或 False。默认 False。new_tag_text如果allow_add为 true,则显示在实体后面的文本。默认为 " (NEW)"。new_tag_prefix新标签的前缀标识符,默认为 "__"。你的实际值开头不能包含这些符号。tag_separators一个 JavaScript 分隔符数组,用于自动分割标签。
delay按键后触发另一个 AJAX 请求前的延迟(毫秒)。默认为 250 ms。placeholder占位符文本。languagei18n 语言代码。默认为 en。theme默认为 'default'。cache启用 AJAX 缓存。每个 'term' 查询的结果将被缓存。cache_timeout缓存查询的时间(毫秒)。将设置为0将导致缓存永远不会超时 (60000 = 60 seconds)transformer如果需要如以下描述的灵活性,则为自定义转换器的完全限定类名。autostart确定是否在文档准备就绪时自动调用 select2 jQuery 代码。默认为 true,提供正常操作。width如果不为 null,则设置 data-width 属性。默认为 null。class_type可选值,将作为查询字符串参数添加到 AJAX 请求中。render_html这将在 ['html'] 下渲染你的结果。
远程查询的 URL 可以通过两种方式之一给出:remote_route 是 Symfony 路由。可以可选地指定 remote_params 来提供参数。或者,可以使用 remote_path 直接指定 URL。
您可以使用 query_parameters 在远程_params 需要动态更改时使用。您可以使用 $('#elem').data('query-parameters', { /* new params */ }); 来更改它们。
可以在您的 config/packages/tetranzselect2entity.yaml 文件中更改默认值,格式如下。
tetranz_select2_entity: minimum_input_length: 2 page_limit: 8 allow_clear: true delay: 500 language: 'fr' theme: 'default' cache: false cache_timeout: 0 scroll: true object_manager: 'manager_alias' render_html: true
AJAX 响应
控制器应返回一个以下格式的 JSON 数组。属性必须是 id 和 text。
[ { id: 1, text: 'Displayed Text 1' }, { id: 2, text: 'Displayed Text 2' } ]
无限滚动
如果您通过Select2的“无限滚动”功能分页显示结果,您可以选择继续返回上面显示的相同数组(为了向后兼容,此包将自动尝试确定是否需要更多结果),或者返回下面显示的对象,以便对分页结果有更精细的控制。
如果还有更多结果需要加载,则more字段应为true。
{ results: [ { id: 1, text: 'Displayed Text 1' }, { id: 2, text: 'Displayed Text 2' } ], more: true }
获取结果的控制器操作将接收一个参数page,表示应该加载哪一页的结果。如果您将滚动设置为true,则必须在查询中处理页面参数。如果不这样做,会发生奇怪的事情。
自定义选项文本
如果您需要更灵活地显示每个选项的文本,例如显示实体中几个字段的值或显示图像,您可以定义自己的自定义转换器。您的转换器必须实现DataTransformerInterface。最简单的方法可能是扩展EntityToPropertyTransformer或EntitiesToPropertyTransformer,并重新定义transform()方法。这样,您就可以返回任何您想要的文本,而不仅仅是单个实体属性。
以下是一个示例,返回国家名称和大洲(Country实体中的两个不同属性)
$builder ->add('country', Select2EntityType::class, [ 'multiple' => true, 'remote_route' => 'tetranz_test_default_countryquery', 'class' => '\Tetranz\TestBundle\Entity\Country', 'transformer' => '\Tetranz\TestBundle\Form\DataTransformer\CountryEntitiesToPropertyTransformer', ]);
在transform中设置数据数组如下
$data[] = array( 'id' => $country->getId(), 'text' => $country->getName().' ('.$country->getContinent()->getName().')', );
您的自定义转换器和相应的Ajax控制器应返回以下格式的数组
[ { id: 1, text: 'United Kingdom (Europe)' }, { id: 1, text: 'China (Asia)' } ]
如果您使用的是allow_add选项,并且您的实体需要除了text_property字段以外的其他字段才能有效,您可能需要扩展EntitiesToPropertyTransformer来添加缺失的字段,创建 doctrine prePersist 监听器,或者在新数据提交后在表单视图中添加缺失的数据。
添加新标签
如果您想通过Select2标签创建新实体,可以使用allow_add选项集来启用它。
例如
$builder ->add('tags', Select2EntityType::class, [ 'remote_route' => 'tetranz_test_tags', 'class' => '\Tetranz\TestBundle\Entity\PostTags', 'text_property' => 'name', 'multiple' => true, 'allow_add' => [ 'enabled' => true, 'new_tag_text' => ' (NEW)', 'new_tag_prefix' => '__', 'tag_separators' => '[",", " "]' ], ]);
添加标签时需要考虑的一些事项
- 您的数据不应有任何可能与
new_tag_prefix的前缀匹配的机会。如果有,请将其更改为其他内容,如‘**’或‘$$’。 tag_separators与Select2选项相同。它应该是一个javascript数组。- 如果您想允许添加实体,并且该实体除了
text_property中指定的字段外还有其他必填字段,您必须在表单提交中添加它们或添加到doctrine实体的prePersist钩子中。 - 如果您使用的是“tags”以单条输入模式创建新实体,请注意您需要删除空格作为分隔符,否则您将无法在此实体中输入空格字符。
$builder ->add('tags', Select2EntityType::class, [ ... 'allow_add' => [ ... 'tag_separators' => '[",", ""]' // No Space here ], ]);
在请求中包含其他字段值
如果您需要包含其他字段值,因为选择取决于它,您可以通过添加req_params选项来实现。键是查询字符串中参数的名称,值是FormView中的路径(如果您不知道路径,您可以在模板中执行类似{{ dump(form) }}的操作。)
property选项指的是用作标签和搜索项的实体字段。
在回调中,您将获得QueryBuilder作为参数来修改结果查询和数据对象(data可以是简单的Request对象或纯数组。有关详细信息,请参阅AutocompleteService.php。)
$builder ->add('firstName', TextType::class) ->add('lastName', TextType::class) ->add('state', EntityType::class, array('class' => State::class)) ->add('county', Select2EntityType::class, [ 'required' => true, 'multiple' => false, 'remote_route' => 'ajax_autocomplete', 'class' => County::class, 'minimum_input_length' => 0, 'page_limit' => 10, 'scroll' => true, 'allow_clear' => false, 'req_params' => ['state' => 'parent.children[state]'], 'property' => 'name', 'callback' => function (QueryBuilder $qb, $data) { $qb->andWhere('e.state = :state'); if ($data instanceof Request) { $qb->setParameter('state', $data->get('state')); } else { $qb->setParameter('state', $data['state']); } }, ]) ->add('city', Select2EntityType::class, [ 'required' => true, 'multiple' => false, 'remote_route' => 'ajax_autocomplete', 'class' => City::class, 'minimum_input_length' => 0, 'page_limit' => 10, 'scroll' => true, 'allow_clear' => false, 'req_params' => ['county' => 'parent.children[county]'], 'property' => 'name', 'callback' => function (QueryBuilder $qb, $data) { $qb->andWhere('e.county = :county'); if ($data instanceof Request) { $qb->setParameter('county', $data->get('county')); } else { $qb->setParameter('county', $data['county']); } }, ]);
因为请求的处理通常非常相似,所以您可以使用一个服务来帮助您处理结果。要使用它,只需在您的控制器中添加一个路由即可
/** * @param Request $request * * @Route("/autocomplete", name="ajax_autocomplete") * * @return Response */ public function autocompleteAction(Request $request) { // Check security etc. if needed $as = $this->get('tetranz_select2entity.autocomplete_service'); $result = $as->getAutocompleteResults($request, YourFormType::class); return new JsonResponse($result); }
模板化
现在已将通用模板添加到捆绑包中。如果您需要在选择结果中渲染HTML代码,请将render_html选项设置为true,并在控制器中返回如下所示的数据:
[ { id: 1, text: 'United Kingdom (Europe)', html: '<img src="images/flags/en.png" />' }, { id: 2, text: 'China (Asia)', html: '<img src="images/flags/ch.png">' } ]
如果您需要进一步使用模板,您需要按以下方式重写.select2entity()方法。
如果您需要在Select2中使用[模板化](https://select2.org/dropdown#templating),您可以考虑以下示例,它显示了每个选项旁边的国家国旗。您的自定义转换器应返回如下所示的数据
[ { id: 1, text: 'United Kingdom (Europe)', img: 'images/flags/en.png' }, { id: 2, text: 'China (Asia)', img: 'images/flags/ch.png' } ]
您需要定义自己的JavaScript函数select2entityAjax,该函数扩展了原始的select2entity函数,并显示带有图像的自定义模板
$.fn.select2entityAjax = function(action) { var action = action || {}; var template = function (item) { var img = item.img || null; if (!img) { if (item.element && item.element.dataset.img) { img = item.element.dataset.img; } else { return item.text; } } return $( '<span><img src="' + img + '" class="img-circle img-sm"> ' + item.text + '</span>' ); }; this.select2entity($.extend(action, { templateResult: template, templateSelection: template })); return this; }; $('.select2entity').select2entityAjax();
此脚本将为具有select2entity类的所有元素全局添加功能,但如果未传递img,它将像原始的select2entity一样工作。您应将'autostart' => false添加到表单中,以确保JavaScript代码正确运行。
->add('contry', Select2EntityType::class, [ 'remote_route' => 'country_select2_query', 'autostart' => false, ])
您还需要重写以下模板块
{% block tetranz_select2entity_widget_select_option %}
<option value="{{ label.id }}" selected="selected"
{% for key, data in label %}
{% if key not in ['id', 'text'] %} data-{{ key }}="{{ data }}"{% endif %}
{% endfor %}>
{{ label.text }}
</option>
{% endblock %}
此块将所有需要添加到JavaScript函数select2entityAjax中的附加数据添加进去,例如数据属性。在这种情况下,我们传递了data-img。
主题
Select2支持使用theme选项自定义主题,因此您可以将Select2样式与您的应用程序的其他部分保持一致。有关Bootstrap4主题,请参阅https://github.com/ttskch/select2-bootstrap4-theme
嵌入集合表单
如果您使用嵌入式集合表单和data-prototype在表单中添加新元素,您需要以下JavaScript,它将监听添加的元素.select2entity
$('body').on('click', '[data-prototype]', function(e) { $(this).prev().find('.select2entity').last().select2entity(); });

