我有一个SPA web应用程序,使用AngularJS
作为前端,Symfony2
作为后端。
我用FOSUserBundle
处理User
。
我现在想做的是使用AngularJS
方法注册我的User
也就是通过Ajax
我的问题是每当我提交表单时,它都会在控制台日志中打印"invalid form"
。
这是我目前的进度:
new.html
<form class="form-group text-left" ng-submit="submit()" novalidate name="userFrm">
<div class="form-group">
<label for="user.email" class="required">Email</label>
<input id="user.email" name="user.email" class="form-control" type="text" ng-model="user.email" />
</div>
<div class="form-group">
<label for="user.username" class="required">Username</label>
<input id="user.username" name="user.username" class="form-control" type="text" ng-model="user.username" />
</div>
<div class="form-group">
<label for="user.plainPassword" class="required">Password</label>
<input id="user.plainPassword" name="user.plainPassword" class="form-control" type="password" ng-model="user.plainPassword" />
</div>
<div class="form-group">
<label for="confirmPassword" class="required">Confirm Password</label>
<input id="confirmPassword" name="confirmPassword" compare-to="user.plainPassword" class="form-control" type="password" ng-model="confirmPassword" />
</div>
<input type="submit" value="Register" ng-disabled="userFrm.$invalid" class="btn btn-primary center-block col-lg-2" />
</form>
new.js
'use strict';
(function () {
angular.module('myApp.user.new', [])
.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('user.new', {
url: "/new",
controller: "NewUserCtrl",
templateUrl: PATH + 'user/new/new.html'
});
}])
.controller('NewUserCtrl', ["$scope", "$http", "$state", function ($scope, $http, $state) {
var success = function (response) {
var valid = response.data.valid;
if (valid) {
$state.go('home');
} else {
console.log("invalid form");
}
};
var error = function (reason) {
console.log("Submission failed");
};
$scope.submit = function () {
var formData = {
fos_user_registration: $scope.user,
confirmPass: $scope.confirmPassword
};
$http.post(Routing.generate('fos_user_registration_register'), $.param(formData), {
headers: {'Content-Type': 'application/x-www-form- urlencoded'}
})
.then(success, error);
};
}]);
}());
RegistrationController.php
(从FOSUserBundle覆盖)
public function registerAction(Request $request) {
/** @var $formFactory FOSUserBundleFormFactoryFactoryInterface */
$formFactory = $this->get('fos_user.registration.form.factory');
/** @var $userManager FOSUserBundleModelUserManagerInterface */
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->createUser();
$user->setEnabled(true);
$form = $formFactory->createForm();
$form->setData($user);
$form->handleRequest($request);
if ($form->isValid()) {
$user->addRole('ROLE_ADMIN');
$userManager->updateUser($user);
$response = ['valid' => true];
return new JsonResponse($response);
}
$response = ['valid' => false];
return new JsonResponse($response);
}
我在您的表单中没有看到CSRF令牌。如果没有CSRF令牌,您的表单可能无法验证。先检查这里;http://symfony.com/doc/current/cookbook/security/csrf_in_login_form.html
此外,为了完全兼容,使用twig模板引擎生成表单可能会更好。在这里看到的;http://symfony.com/doc/current/book/forms.html
为了进一步调查为什么您的表单没有被验证,您可以为$form->isValid()
检查编写一个else块,并使用答案中的方法来查看表单错误。您可以检查表单没有被验证的原因。https://stackoverflow.com/a/17428869/3399234
我想到了一个解决办法。我使用了包含symfony 2.6.10的Vagrant配置。我已经覆盖了RegistrationFormType,将它放在我自己的bundle中,并将其作为服务注入,就像FOS一样。我用我自己的服务别名替换了FOS登记表。所以我设法关闭csrf保护在我的覆盖RegistrationFormType。
还添加了将plainPassword设置为用户模型,以修复USerManager中的持久性错误。
控制器,覆盖FOS注册控制器。
<?php
namespace AcmeWebBundleController;
use SymfonyBundleFrameworkBundleControllerController;
use FOSUserBundleControllerRegistrationController as BaseController;
use SymfonyComponentHttpFoundationRequest as Request;
use SymfonyComponentHttpFoundationJsonResponse as JsonResponse;
class RegistrationController extends BaseController
{
public function registerAction()
{
$request = Request::createFromGlobals();
$form = $this->container->get('fos_user.registration.form');
/** @var $userManager FOSUserBundleModelUserManagerInterface */
$userManager = $this->container->get('fos_user.user_manager');
$user = $userManager->createUser();
$form->setData($user);
$form->handleRequest($request);
if ($form->isValid()) {
$user->setEnabled(true);
$user->addRole('ROLE_ADMIN');
$userManager->updateUser($user);
$response = ['valid' => true];
return new JsonResponse($response);
} else {
$string = (string) $form->getErrors(true, false);
//Show errors
$response = ['valid' => false];
return new JsonResponse($response);
}
return $this->container->get('templating')->renderResponse('AcmeWebBundle:Default:index.html.twig');
}
}
被覆盖的FOS注册表,
<?php
//AcmeWebBundleFormTypeRegistrationFormType.php
namespace AcmeWebBundleFormType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
class RegistrationFormType extends AbstractType
{
private $class;
/**
* @param string $class The User class name
*/
public function __construct($class)
{
$this->class = $class;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => $this->class,
'intention' => 'registration',
'csrf_protection' => false, //this line does the trick ;)
));
}
public function getParent()
{
return 'fos_user_registration';
}
public function getName()
{
return 'acme_user_registration';
}
}
Services.yml
services:
acme.registration.form.type:
class: AcmeWebBundleFormTypeRegistrationFormType
arguments: ["%fos_user.model.user.class%"]
tags:
- { name: form.type, alias: acme_user_registration }
index.html.twig
<script type="text/javascript">
var app = angular.module('myApp', []);
app.controller('NewUserCtrl', ["$scope", "$http", function ($scope, $http) {
var success = function (response) {
var valid = response.data.valid;
if (valid) {
$state.go('home');
} else {
console.log("invalid form");
}
};
var error = function (reason) {
console.log("Submission failed");
};
$scope.submit = function () {
var formData = {
fos_user_registration_form: $scope.user
};
$http.post('<YOUR URL HERE>', $.param(formData), {
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).then(success, error);
};
}]);
</script>
<div id="content" ng-app="myApp" ng-controller="NewUserCtrl" >
<form class="form-group text-left" ng-submit="submit()" novalidate name="userFrm">
<div class="form-group">
<label for="user.email" class="required">Email</label>
<input id="user.email" name="user.email" class="form-control" type="text" ng-model="user.email" />
</div>
<div class="form-group">
<label for="user.username" class="required">Username</label>
<input id="user.username" name="user.username" class="form-control" type="text" ng-model="user.username" />
</div>
<div class="form-group">
<label for="user.plainPassword.first" class="required">Password</label>
<input id="user.plainPassword.first" name="user.plainPassword.first" class="form-control" type="password" ng-model="user.plainPassword.first" />
</div>
<div class="form-group">
<label for="user.plainPassword.second" class="required">Confirm Password</label>
<input id="user.plainPassword.second" name="user.plainPassword.second" compare-to="user.plainPassword.first" class="form-control" type="password" ng-model="user.plainPassword.second" />
</div>
<input type="submit" value="Register" ng-disabled="userFrm.$invalid" class="btn btn-primary center-block col-lg-2" />
</form>
</div>
这是config中的fos_user配置。当FOS用户包的注册表单被调用时,使用覆盖的表单更改默认表单。
config.yml
fos_user:
registration:
form:
type: acme_user_registration
就是这样,我可以发布表单并将用户持久化到数据库,然后按预期返回{"valid":true}
响应。最后,我有机会学习如何将AngularJS注入到Symfony 2中,为此干杯。