Symfony 保留表单值教程展示了在表单提交失败后如何在表单提交后保持表单值。 在本教程中,我们进行传统的表单提交; 我们不使用表单构建器。

Symfony

Symfony 是一组可重用的 PHP 组件和一个用于 Web 项目的 PHP 框架。 Symfony 于 2005 年发布为免费软件。Symfony 的原始作者是 Fabien Potencier。 Symfony 受到 Spring 框架的极大启发。

保留表单值

用户提交表单后,将由应用进行验证。 当验证失败时,应用将用户重定向回表单,显示验证错误。 最好将已输入的值保留在表格中。

Symfony 保留表单值示例

在示例中,我们有一个简单的表单,其中包含两个字段:名称和电子邮件。 提交表单后,我们检查 CSRF 保护并使用 Symfony 的Validator验证输入值。 我们将输入的值存储到会话中,以在提交失败时取回它们。

建立应用

我们首先使用composer建立应用。

$ composer create-project symfony\skeleton formkeepvals
$ cd formkeepvals

我们创建一个新的 Symfony 骨架项目,然后进入新创建的项目目录。

$ composer require twig annot validator

我们安装了三个基本的 Symfony 包:twigannotvalidator。 包可能具有别名。 例如,symfony/validator具有两个别名:validatorvalidation。 有关更多详细信息,请检查 Symfony 食谱服务器。

$ composer require symfony/security-csrf
$ composer require symfony/monolog-bundle

跨站点请求伪造需要security-csrf包,而日志记录则需要monolog-bundle包。

$ composer require symfony/property-access

我们安装了PropertyAccess组件,该组件用于方便读取和写入对象和数组的属性/键。

$ composer require maker server --dev

我们安装制造商组件和开发服务器。

$ php bin/console make:controller HomeController

我们创建一个HomeController。 控制器将表单发送给客户端。

src/Controller/HomeController.php

<?phpnamespace App\Controller;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;class HomeController extends AbstractController
{/*** @Route("/home", name="home")*/public function index(){return $this->render('home/index.html.twig');}
}

这是一个简单的控制器,可将包含 Web 表单的视图发送给用户。

$ php bin/console make:controller MessageController

我们创建一个MessageController来响应表单提交。

src/Controller/MessageController.php

<?phpnamespace App\Controller;use App\Service\ValidationService;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;class MessageController extends AbstractController
{/*** @Route("/message", name="message")*/public function index(Request $request, ValidationService $validator){$token = $request->get("token");$valid = $validator->validateToken($token);if (!$valid) {return new Response("Operation not allowed", Response::HTTP_BAD_REQUEST,['content-type' => 'text/plain']);}$name = $request->request->get("name");$email = $request->request->get("email");$input = ['name' => $name, 'email' => $email];$errorMessages = $validator->validateInput($input);if (count($errorMessages) > 0){$session = $request->getSession();$session->set('name', $name);$session->set('email', $email);foreach ($errorMessages as $key => $val) {$this->addFlash($key, $val);}return $this->redirectToRoute('home');} else {return new Response("User saved", Response::HTTP_OK,['content-type' => 'text/plain']);}}
}

MessageController中,我们检查 CSRF 令牌,验证表单输入值,并将响应发送回客户端。

public function index(Request $request, ValidationService $validator)
{

验证委派给ValidationService,后者被注入到方法中。

$token = $request->get("token");$valid = $validator->validateToken($token);if (!$valid) {return new Response("Operation not allowed", Response::HTTP_BAD_REQUEST,['content-type' => 'text/plain']);
}

我们获得 CSRF 令牌并对其进行验证。 如果验证失败,我们将带有错误消息的响应发送回客户端。

$name = $request->request->get("name");
$email = $request->request->get("email");$input = ['name' => $name, 'email' => $email];$errorMessages = $validator->validateInput($input);

我们检索表单输入值,并使用验证服务对其进行验证。 如果验证服务失败,它将返回错误消息。

if (count($errorMessages) > 0)
{$session = $request->getSession();$session->set('name', $name);$session->set('email', $email);
...

如果有一些错误消息,我们将输入值添加到会话中,以便我们可以在重定向后检索它们。

foreach ($errorMessages as $key => $val) {$this->addFlash($key, $val);
}

我们将消息添加到 Flash 包中; 闪存袋用于存储临时消息,例如我们的验证消息。

return $this->redirectToRoute('home');

我们使用redirectToRoute()重定向回表单。

src/Service/ValidationService.php

<?phpnamespace App\Service;use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;class ValidationService
{private $tokenManager;private $validator;private $accessor;private $logger;public function __construct(CsrfTokenManagerInterface $tokenManager,ValidatorInterface $validator, PropertyAccessorInterface $accessor,LoggerInterface $logger){$this->tokenManager = $tokenManager;$this->validator = $validator;$this->accessor = $accessor;$this->logger = $logger;}public function validateToken($token): bool{$csrf_token = new CsrfToken('myform', $token);$isValid = $this->tokenManager->isTokenValid($csrf_token);if (!$isValid) {$this->logger->error("CSRF failure");}return $isValid;}public function validateInput(array $input): array{$constraints = new Assert\Collection(['name' => [new Assert\Length(['min' => 2]), new Assert\NotBlank],'email' => [new Assert\Email, new Assert\NotBlank],]);$violations = $this->validator->validate($input, $constraints);if (count($violations) > 0) {$this->logger->info("Validation failed");$messages = [];foreach ($violations as $violation) {$this->accessor->setValue($messages,$violation->getPropertyPath(),$violation->getMessage());}return $messages;} else {return [];}}
}

ValidationService检查 CSRF 令牌并验证输入。

public function __construct(CsrfTokenManagerInterface $tokenManager,ValidatorInterface $validator, PropertyAccessorInterface $accessor,LoggerInterface $logger)
{$this->tokenManager = $tokenManager;$this->validator = $validator;$this->accessor = $accessor;$this->logger = $logger;
}

我们在构造器中注入了四个对象:令牌管理器,验证器,属性访问器和记录器。

public function validateToken($token): bool
{$csrf_token = new CsrfToken('myform', $token);$isValid = $this->tokenManager->isTokenValid($csrf_token);if (!$isValid) {$this->logger->error("CSRF failure");}return $isValid;
}

此代码使用令牌管理器验证 CSRF 令牌。

$constraints = new Assert\Collection(['name' => [new Assert\Length(['min' => 2]), new Assert\NotBlank],'email' => [new Assert\Email, new Assert\NotBlank],
]);

这些是验证表单输入的约束。

$violations = $this->validator->validate($input, $constraints);

使用验证器,我们可以验证表单输入值。

if (count($violations) > 0) {$this->logger->info("Validation failed");$messages = [];foreach ($violations as $violation) {$this->accessor->setValue($messages,$violation->getPropertyPath(),$violation->getMessage());}return $messages;
} else {return [];
}

如果存在一些违规行为,我们将记录故障并生成验证错误消息。 为了构建消息,我们利用 Symfony 属性访问器。 如果没有违规,我们将返回一个空数组。

templates/home/index.html.twig

{% extends 'base.html.twig' %}{% block title %}Home page{% endblock %}{% block stylesheets %}
<style>.topmargin {margin-top: 10px;}
</style>
{% endblock %}{% block body %}<section class="ui container topmargin"><form class="ui form" action="message" method="post"><input type="hidden" name="token" value="{{ csrf_token('myform') }}" />{% for msg in app.flashes('name') %}<div class="ui small red message">{{ msg }}</div>{% endfor %}<div class="field"><label>Name:</label><input type="text" name="name" value="{{app.session.get('name')}}"></div>{% for msg in app.flashes('email') %}<div class="ui small red message">{{ msg }}</div>{% endfor %}<div class="field"><label>Email</label><input type="text" name="email" , value="{{app.session.get('email')}}"></div><button class="ui button" type="submit">Send</button></form></section>{% endblock %}

主页上有一个表格。 该表格包含两个字段:姓名和电子邮件。

<input type="hidden" name="token" value="{{ csrf_token('myform') }}" />

它还包含一个隐藏字段,以防止跨站点请求伪造。

{% for msg in app.flashes('name') %}
<div class="ui small red message">{{ msg }}
</div>
{% endfor %}

如果闪存包中有一些错误消息,我们将显示它们。

<input type="text" name="name" value="{{app.session.get('name')}}">

输入标签从会话中检索其值(如果有)。 重定向到表单后,这很有用。

templates/base.html.twig

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>{% block title %}Welcome!{% endblock %}</title><link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css"rel="stylesheet">{% block stylesheets %}{% endblock %}</head><body>{% block body %}{% endblock %}<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.1/semantic.min.js"></script>{% block javascripts %}{% endblock %}</body>
</html>

这是基本的 Twig 模板。 它包含语义 UI CSS 框架。

在本教程中,我们验证了 Symfony 应用中的简单表单。

Symfony 保留表单值相关推荐

  1. 将Jquery序列化后的表单值转换成Json

    来源于:https://segmentfault.com/a/1190000000473625 小朋友有一个表单,他想以Json的方式获取到表单的内容.小朋友尝试了以下方式. 通过$("#f ...

  2. oracle秘钥到期,Oracle – 更新加入 – 非密钥保留表

    我试图复制一个Ingres"tbl2"中的更新tbl1命令,这在Oracle中并不完全. 所以我使用"update(select tbl1 join tbl2 -)&qu ...

  3. javascript获取表单值的7种方式

    见代码: <!doctype html> <html lang="en"> <head><meta charset="UTF-8 ...

  4. 选下拉框的的值对应上传相应的图片_vue.js如何拿到多种类型表单值提交到后台,包含上传图片、单选、复选、文本框、下拉列表框...

    2016-01-17 编辑更新 vue.js如何拿到多种类型表单值提交到后台,包含上传图片.单选.复选.文本框.下拉列表框 下面的html包括多种类型的表单,其中包括图片上传,如何拿到这些表单的值提交 ...

  5. twig php代碼,有没有办法在wordpress的.twig文件中编写php代码?我试图使用.twig模板文件中的表单值发送邮件...

    有没有办法在wordpress的.twig文件中编写php代码?我正在尝试使用.twig模板文件中的表单值发送邮件. 第PAGE-SHORTEFORM.TWIG页 {% extends "b ...

  6. JQ手册 JQ方法大全 jq获取表单值与赋值代码 50个JQ的例子

    http://hemin.cn/jq/index.html http://www.365mini.com/page/jquery-jquery.htm JQ方法大全http://wenku.baidu ...

  7. mysql中清空数据库数据保留表结构

    – mysql导出视图以及表结构 #mysqldump -uuser -ppassword --d database_name> database_name_date.sql – 只导出数据不导 ...

  8. 【jQuery - serializeArray 序列化表单值并转为键值对】

    原文找不到了,先挂原创.原作者看到,请联系我,我改为转载. /*** 序列化表单值并转为键值对*/ function getFormJson(form) { var o = {}; var a = $ ...

  9. SQL中删除数据,保留表结构。

    truncate和delete的区别 在SQL中,delete能快速删除数据表中所有记录,但保留数据表结构的语句是Truncate. 使用Truncate删除所有行,该语句总是比不带条件的DELETE ...

最新文章

  1. 2011面试题大汇总
  2. Visual Studio 2005 创建Windows服务程序(C#)
  3. 数据中心支持物联网的5种方式
  4. 上传镜像文件到服务器,通过把docker镜像保存为文件载入到别的服务器
  5. Fraction+mysql_MySQL 数据类型总结
  6. 使用 OAuth2-Server-php 搭建 OAuth2 Server
  7. 完全复制一个dict_Redis主从复制getshell技巧
  8. android中访问手机存储空间,android – 访问手机内部存储以推入SQLite数据库文件...
  9. 【牛客 - 327G】处女座与复读机(可编辑距离问题,dp)
  10. Java 中访问路径的问题
  11. 如何删除Win All的流氓程序文件
  12. J2ME游戏中的图片处理
  13. python中一切数据都是对象吗_Python 对象中的数据类型
  14. 证券基金行业IT运维“远景”如何应对?
  15. 等待队列中为什么需要互斥锁?一个线程在等待时被唤醒后会做什么?安全队列的代码实现
  16. selenium webdriver 通信过程
  17. java字符串类型和时间类型的转换
  18. 互联网智商测试:搜索引擎谁的“智商”更高?
  19. [曲线拟合]使用Tensorflow拟合COS函数
  20. 线性代数(一)矩阵和方程组

热门文章

  1. java把一段英文拆成单词_如何在java中将句子拆分成单词和标点符号
  2. 增压撬启停控制优化及纳入GE UCP控制系统可行性研究
  3. [笔记] 最优化方法 - 凸集
  4. 2019.03.16【NOIP提高组】模拟 B 组 电费结算(electric)
  5. 标签平滑深度学习:Google Brain解释了为什么标签平滑有用以及什么时候使用它(SOTA tips)​...
  6. 制药行业如何应用二维码
  7. 随身WiFi制作Linux服务器
  8. 酷狗app signature
  9. guidata handles理解
  10. 关于axes(handles.axes)报错,提示未定义handles或类handles.axes