边栏搜索框的实现和模板共用-使用TEEBB快速搭建您的网站
TEEBB提供了搜索block类型,在命令行中输入
symfony console debug:sonata:block
找到teebb.core.block.search
类型,
>> teebb.core.block.search
label ""
translation_domain "messages"
template "@TeebbCore\/blocks\/search_form.html.twig"
route "teebb_content_index"
form_class ""
property "title"
extra {"fields":[]}
双击shift键,勾选右上角,我们查看系统自带的搜索block模板,模板提供了form表单,表单的action地址对应block类型的route参数。route
是搜索页面的路由名称。form_class
:是form表单的样式类。property
:表单行的name。暂时忽略extra参数。
在对应代码位置,注释原有代码,使用sonata_block_render函数渲染搜索block类型, route参数输入search
,现在还没有这个路由, 回到FrontController类创建search路由。
{{ sonata_block_render({type:'teebb.core.block.search'}, {
route: 'search',
template: 'blocks/search_form.html.twig'
}) }}
创建一个空的Action函数,直接复制index()进行修改,先修改路由路径和名称,修改render方法中的模板,对应的创建search_resuls.html.twig文件。 删除index和search方法的 controller_name参数。如果传入模板中的参数为空,可以省略。
回到动态列表页面,刷新! 搜索框已经出现了,但是样式和模板的不同,你可以复制html模板代码来定义自己的模板。在表单行中任意输入点文字、点击按钮。跳转到了search路由,并且表单行的数据以GET方式添加到了url后面。title
就是搜索block类型的property参数。 现在,我们来完成搜索Action函数的功能。回到FrontController search函数。
讲些Symfony知识: Symfony作为MVC框架实现了PSR容器接口(弹出PSR文档),我们打开config目录下services.yaml文件, 在services键下方:src目录下的`exclude`配置以外的所有类都可以叫作“服务”,Entity目录下的类是Symfony框架的Model类型。 在_defaults
键下方看到 autowire
和 autoconfigure
配置项,如果这两项为真,Symfony框架会将src目录中的类自动装配和自动配置并添加到Container容器中。在Container容器中的服务可以通过依赖注入的方式直接使用。
TEEBB也提供了很多服务,一般第三方Bundle中提供的服务都通过配置的形式添加到容器中,在TeebbCoreBundle -> Resources目录下的config目录中,你可以看到一些服务的具体配置。
回到FrontController类我们可以直接把容器中的服务依赖注入到Action函数中。
传入第一个参数,选择 HttpFoundation
组件提供的 Request
服务,Request
对HTTP请求进行了封装,可以很方便的获取HTTP请求参数。
我们刚刚传入了title请求参数,输入:
$title = $request->get('title', '');
get的第二个参数是默认值,如果没有传入title参数则返回默认值。使用dd()方法来进行查看。
我们要根据传入的title值进行内容搜索,并且只对内容的标题进行模糊查询。现在注入第二个参数EntityManagerInterface $em
,EntityManagerInterface接口的对象可以管理Entity对象在数据库中的数据,并提供了一些操作数据库的方法。
TEEBB中内容类型对应的Entity类是Content,获取Content类的Repository服务类,
/**@var BaseContentRepository $baseContentRepository * */
$baseContentRepository = $em->getRepository(Content::class);
BaseContentRepository
类的createPaginator()
方法可以按条件查询并将获取到的结果进行分页。第一个参数是查询条件,第二个参数是结果排序条件。
$criteria = ['bundle' => 'content'];
if ($title !== '') {
$criteria = array_merge($criteria, ['title' => '%' . $title . '%']);
}
/**
* @var Pagerfanta $paginator
*/
$paginator = $baseContentRepository->createPaginator($criteria, ['id' => 'DESC']);
将$paginator
传入模板文件,也将当前的查询关键字传入模板,方便进行提醒。
查询到的结果页面样式和内容列表页的模板一样,将list_type_contents.html.twig
中的block区块代码复制到search_results.html.twig
文件。
复制title block:
{% block title %}
搜索"{{ keyword }}"结果
{% endblock %}
复制list_page_title 区块
{% block list_page_title %}
<section id="topTitle" class="bg-light">
<div class="container text-center">
<div class="row pt-4">
<div class="col-12">
<h1 class="font-weight-bold normal-title text-muted">
搜索"{{ keyword }}"结果
</h1>
</div>
</div>
...
</div>
</section>
{% endblock %}
复制粘贴content block中代码。 刷新页面,在右侧搜索框输入公告
这是我们唯一的公告内容标题中包含的关键字。回车,结果显示了。 但是,模板文件中有大量代码重复了,我可以把列表页左右两侧的代码提取到单独的文件中。 创建content_list.html.twig
和side.html.twig
文件。剪切并粘贴对应的代码。 在search_results.html.twig中对应位置引入这两个文件。
{% include 'front/content_list.html.twig' with _context %}
{% include 'front/side.html.twig' with _context %}
Twig中使用with
关键字可以在include
模板文件时对模板文件传入参数 _context
关键字是当前页面的上下文数据,这样在模板文件中也可以使用当前页面的所有参数数据。
对应的我们修改list_type_contents.html.twig
引入文件。 注意:在content_list.html.twig
文件中,是通过对paginator
参数进行的遍历。所以,如果你想共用这个模板,请确保你的Action函数中传入了paginator
参数并且是分页器Pagerfanta
对象。
回到动态列表页,显示正常,在搜索框中输入“内容”,回车,搜索结果页也成功显示了。 如果你想完整的实现分页功能,还需要在搜索Action中传入另两个参数,page用于当前的页码,limit当前列表项数量限制。 对paginator对象设置这两个参数
$page = $request->get('page', 1);
$limit = $request->get('limit', 10);
$paginator->setMaxPerPage($limit);
$paginator->setCurrentPage($page);
在搜索结果页面url中传入参数limit=1,搜索结果进行了分页,并成功显示了。
下一节,我们来完成边栏剩下的功能。