Symfony2 InvalidArgumentException: The current node list is empty - symfony

I'm doing functional testing and I am getting the error
InvalidArgumentException: The current node list is empty
This is my code
public function testThis(){
$requestContent = [
'val1' => '324343',
'valname' => '"Benjamin"',
'valLast' => '"A"',
'valnum' => '44343',
'hndval1' => '0000',
'hdnval2' => '0000',
'hndval3' => '1111',
'hndref' => '"ThisIsAtest"',
'hdnMessage' => '"I am a message"'
];
$crawler = $this->client->request('GET', '/');
$submitButton = $crawler->selectButton('btnSubmit');
$form = $submitButton->form($requestContent);
print_r($form);
$this->client->followRedirects(true);
$crawler = $this->client->submit($form);
$response = $this->client->getResponse();
$request = $this->client->getRequest();
print_r($crawler->html());
$this->assertRegExp('/\/nextPage', $request->getUri());
print_r($request->getUri());
$a = $crawler->filter('input[name="pageName"]');
$this->assertContains(
"True",
$a->attr('value')
);
}
I think it is getting error in this :
$form = $submitButton->form($requestContent);
Note that $requestContent values are coming from a hidden input type which are all inside the form tag.

You have not posted your HTML so now i assumed your HTML such as :
<html>
<form method='GET' action='your action here'>
/*
* all other html here
*/
<input type='submit' value='Submit' id='btnSubmit' name='btnSubmit'>
</form>
</html>
$submitButton = $crawler->selectButton('btnSubmit');
to change
$submitButton = $crawler->selectButton('Submit');
Because selectButton() accept the button value instead of id or name.
Make sure this is a helpful to you.

You have to provide the text of the button to $crawler->selectButton().
// For a given HTML button:
// <input type="button" value="Upload File" />
// or
// <button type="button">Upload File</button>
$crawler->selectButton("Upload File");
Side note, your regex pattern '/\/nextPage' is invalid. You need to add a closing / --> '/\/nextPage/' // This will match the exact string: "/nextPage"

Related

Google Recaptcha v3 example demo

Until now, I was working with Google Recaptcha v2, but now I want to update my WebApp using the lastest version (v3).
Is it possible to anyone add a fully working Google Recaptcha v3 example for a basic form as I can't find any working demos of it?
I'd really appreciate it.
Thank you very much.
PS: I'm using Java Servlets on the server side, but it doesn't matter if you explain using PHP or whatever.
Simple code to implement ReCaptcha v3
The basic JS code
<script src="https://www.google.com/recaptcha/api.js?render=your reCAPTCHA site key here"></script>
<script>
grecaptcha.ready(function() {
// do request for recaptcha token
// response is promise with passed token
grecaptcha.execute('your reCAPTCHA site key here', {action:'validate_captcha'})
.then(function(token) {
// add token value to form
document.getElementById('g-recaptcha-response').value = token;
});
});
</script>
The basic HTML code
<form id="form_id" method="post" action="your_action.php">
<input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">
<input type="hidden" name="action" value="validate_captcha">
.... your fields
</form>
The basic PHP code
if (isset($_POST['g-recaptcha-response'])) {
$captcha = $_POST['g-recaptcha-response'];
} else {
$captcha = false;
}
if (!$captcha) {
//Do something with error
} else {
$secret = 'Your secret key here';
$response = file_get_contents(
"https://www.google.com/recaptcha/api/siteverify?secret=" . $secret . "&response=" . $captcha . "&remoteip=" . $_SERVER['REMOTE_ADDR']
);
// use json_decode to extract json response
$response = json_decode($response);
if ($response->success === false) {
//Do something with error
}
}
//... The Captcha is valid you can continue with the rest of your code
//... Add code to filter access using $response . score
if ($response->success==true && $response->score <= 0.5) {
//Do something to denied access
}
You have to filter access using the value of $response.score. It can takes values from 0.0 to 1.0, where 1.0 means the best user interaction with your site and 0.0 the worst interaction (like a bot). You can see some examples of use in ReCaptcha documentation.
I thought a fully-functioning reCaptcha v3 example demo in PHP, using a Bootstrap 4 form, might be useful to some.
Reference the shown dependencies, swap in your email address and keys (create your own keys here), and the form is ready to test and use. I made code comments to better clarify the logic and also included commented-out console log and print_r lines to quickly enable viewing the validation token and data generated from Google.
The included jQuery function is optional, though it does create a much better user prompt experience in this demo.
PHP file (mail.php):
Add secret key (2 places) and email address where noted.
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
# BEGIN Setting reCaptcha v3 validation data
$url = "https://www.google.com/recaptcha/api/siteverify";
$data = [
'secret' => "your-secret-key-here",
'response' => $_POST['token'],
'remoteip' => $_SERVER['REMOTE_ADDR']
];
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
# Creates and returns stream context with options supplied in options preset
$context = stream_context_create($options);
# file_get_contents() is the preferred way to read the contents of a file into a string
$response = file_get_contents($url, false, $context);
# Takes a JSON encoded string and converts it into a PHP variable
$res = json_decode($response, true);
# END setting reCaptcha v3 validation data
// print_r($response);
# Post form OR output alert and bypass post if false. NOTE: score conditional is optional
# since the successful score default is set at >= 0.5 by Google. Some developers want to
# be able to control score result conditions, so I included that in this example.
if ($res['success'] == true && $res['score'] >= 0.5) {
# Recipient email
$mail_to = "youremail#domain.com";
# Sender form data
$subject = trim($_POST["subject"]);
$name = str_replace(array("\r","\n"),array(" "," ") , strip_tags(trim($_POST["name"])));
$email = filter_var(trim($_POST["email"]), FILTER_SANITIZE_EMAIL);
$phone = trim($_POST["phone"]);
$message = trim($_POST["message"]);
if (empty($name) OR !filter_var($email, FILTER_VALIDATE_EMAIL) OR empty($phone) OR empty($subject) OR empty($message)) {
# Set a 400 (bad request) response code and exit
http_response_code(400);
echo '<p class="alert-warning">Please complete the form and try again.</p>';
exit;
}
# Mail content
$content = "Name: $name\n";
$content .= "Email: $email\n\n";
$content .= "Phone: $phone\n";
$content .= "Message:\n$message\n";
# Email headers
$headers = "From: $name <$email>";
# Send the email
$success = mail($mail_to, $subject, $content, $headers);
if ($success) {
# Set a 200 (okay) response code
http_response_code(200);
echo '<p class="alert alert-success">Thank You! Your message has been successfully sent.</p>';
} else {
# Set a 500 (internal server error) response code
http_response_code(500);
echo '<p class="alert alert-warning">Something went wrong, your message could not be sent.</p>';
}
} else {
echo '<div class="alert alert-danger">
Error! The security token has expired or you are a bot.
</div>';
}
} else {
# Not a POST request, set a 403 (forbidden) response code
http_response_code(403);
echo '<p class="alert-warning">There was a problem with your submission, please try again.</p>';
} ?>
HTML <head>
Bootstrap CSS dependency and reCaptcha client-side validation
Place between <head> tags - paste your own site-key where noted.
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://www.google.com/recaptcha/api.js?render=your-site-key-here"></script>
HTML <body>
Place between <body> tags.
<!-- contact form demo container -->
<section style="margin: 50px 20px;">
<div style="max-width: 768px; margin: auto;">
<!-- contact form -->
<div class="card">
<h2 class="card-header">Contact Form</h2>
<div class="card-body">
<form class="contact_form" method="post" action="mail.php">
<!-- form fields -->
<div class="row">
<div class="col-md-6 form-group">
<input name="name" type="text" class="form-control" placeholder="Name" required>
</div>
<div class="col-md-6 form-group">
<input name="email" type="email" class="form-control" placeholder="Email" required>
</div>
<div class="col-md-6 form-group">
<input name="phone" type="text" class="form-control" placeholder="Phone" required>
</div>
<div class="col-md-6 form-group">
<input name="subject" type="text" class="form-control" placeholder="Subject" required>
</div>
<div class="col-12 form-group">
<textarea name="message" class="form-control" rows="5" placeholder="Message" required></textarea>
</div>
<!-- form message prompt -->
<div class="row">
<div class="col-12">
<div class="contact_msg" style="display: none">
<p>Your message was sent.</p>
</div>
</div>
</div>
<div class="col-12">
<input type="submit" value="Submit Form" class="btn btn-success" name="post">
</div>
<!-- hidden reCaptcha token input -->
<input type="hidden" id="token" name="token">
</div>
</form>
</div>
</div>
</div>
</section>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('your-site-key-here', {action: 'homepage'}).then(function(token) {
// console.log(token);
document.getElementById("token").value = token;
});
// refresh token every minute to prevent expiration
setInterval(function(){
grecaptcha.execute('your-site-key-here', {action: 'homepage'}).then(function(token) {
console.log( 'refreshed token:', token );
document.getElementById("token").value = token;
});
}, 60000);
});
</script>
<!-- References for the optional jQuery function to enhance end-user prompts -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="form.js"></script>
Optional jQuery function for enhanced UX (form.js):
(function ($) {
'use strict';
var form = $('.contact_form'),
message = $('.contact_msg'),
form_data;
// Success function
function done_func(response) {
message.fadeIn()
message.html(response);
setTimeout(function () {
message.fadeOut();
}, 10000);
form.find('input:not([type="submit"]), textarea').val('');
}
// fail function
function fail_func(data) {
message.fadeIn()
message.html(data.responseText);
setTimeout(function () {
message.fadeOut();
}, 10000);
}
form.submit(function (e) {
e.preventDefault();
form_data = $(this).serialize();
$.ajax({
type: 'POST',
url: form.attr('action'),
data: form_data
})
.done(done_func)
.fail(fail_func);
}); })(jQuery);
I am assuming you have site key and secret in place. Follow this step.
In your HTML file, add the script.
<script src="https://www.google.com/recaptcha/api.js?render=put your site key here"></script>
Also, do use jQuery for easy event handling.
Here is the simple form.
<form id="comment_form" action="form.php" method="post" >
<input type="email" name="email" placeholder="Type your email" size="40"><br><br>
<textarea name="comment" rows="8" cols="39"></textarea><br><br>
<input type="submit" name="submit" value="Post comment"><br><br>
</form>
You need to initialize the Google recaptcha and listen for the ready event. Here is how to do that.
<script>
// when form is submit
$('#comment_form').submit(function() {
// we stoped it
event.preventDefault();
var email = $('#email').val();
var comment = $("#comment").val();
// needs for recaptacha ready
grecaptcha.ready(function() {
// do request for recaptcha token
// response is promise with passed token
grecaptcha.execute('put your site key here', {action: 'create_comment'}).then(function(token) {
// add token to form
$('#comment_form').prepend('<input type="hidden" name="g-recaptcha-response" value="' + token + '">');
$.post("form.php",{email: email, comment: comment, token: token}, function(result) {
console.log(result);
if(result.success) {
alert('Thanks for posting comment.')
} else {
alert('You are spammer ! Get the #$%K out.')
}
});
});
});
});
</script>
Here is the sample PHP file. You can use Servlet or Node or any backend language in place of it.
<?php
$email;$comment;$captcha;
if(isset($_POST['email'])){
$email=$_POST['email'];
}if(isset($_POST['comment'])){
$comment=$_POST['comment'];
}if(isset($_POST['token'])){
$captcha=$_POST['token'];
}
if(!$captcha){
echo '<h2>Please check the the captcha form.</h2>';
exit;
}
$secretKey = "put your secret key here";
$ip = $_SERVER['REMOTE_ADDR'];
// post request to server
$url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($secretKey) . '&response=' . urlencode($captcha);
$response = file_get_contents($url);
$responseKeys = json_decode($response,true);
header('Content-type: application/json');
if($responseKeys["success"]) {
echo json_encode(array('success' => 'true'));
} else {
echo json_encode(array('success' => 'false'));
}
?>
Here is the tutorial link: https://codeforgeek.com/2019/02/google-recaptcha-v3-tutorial/
Hope it helps.
We use recaptcha-V3 only to see site traffic quality, and used it as non blocking. Since recaptcha-V3 doesn't require to show on site and can be used as hidden but you have to show recaptcha privacy etc links (as recommended)
Script Tag in Head
<script src="https://www.google.com/recaptcha/api.js?onload=ReCaptchaCallbackV3&render='SITE KEY' async defer></script>
Note: "async defer" make sure its non blocking which is our specific requirement
JS Code:
<script>
ReCaptchaCallbackV3 = function() {
grecaptcha.ready(function() {
grecaptcha.execute("SITE KEY").then(function(token) {
$.ajax({
type: "POST",
url: `https://api.${window.appInfo.siteDomain}/v1/recaptcha/score`,
data: {
"token" : token,
},
success: function(data) {
if(data.response.success) {
window.recaptchaScore = data.response.score;
console.log('user score ' + data.response.score)
}
},
error: function() {
console.log('error while getting google recaptcha score!')
}
});
});
});
};
</script>
HTML/Css Code:
there is no html code since our requirement is just to get score and don't want to show recaptcha badge.
Backend - Laravel Code:
Route:
Route::post('/recaptcha/score', 'Api\\ReCaptcha\\RecaptchaScore#index');
Class:
class RecaptchaScore extends Controller
{
public function index(Request $request)
{
$score = null;
$response = (new Client())->request('post', 'https://www.google.com/recaptcha/api/siteverify', [
'form_params' => [
'response' => $request->get('token'),
'secret' => 'SECRET HERE',
],
]);
$score = json_decode($response->getBody()->getContents(), true);
if (!$score['success']) {
Log::warning('Google ReCaptcha Score', [
'class' => __CLASS__,
'message' => json_encode($score['error-codes']),
]);
}
return [
'response' => $score,
];
}
}
we get back score and save in variable which we later user when submit form.
Reference:
https://developers.google.com/recaptcha/docs/v3
https://developers.google.com/recaptcha/
I have seen most of the articles that don't work properly that's why new developers and professional developers get confused about it.
I am explaining to you in a very simple way. In this code, I am generating a google Recaptcha token at the client side at every 3 seconds of time interval because the token is valid for only a few minutes that's why if any user takes time to fill the form then it may be expired.
First I have an index.php file where I am going to write HTML and JavaScript code.
<!DOCTYPE html>
<html>
<head>
<title>Google Recaptcha V3</title>
</head>
<body>
<h1>Google Recaptcha V3</h1>
<form action="recaptcha.php" method="post">
<label>Name</label>
<input type="text" name="name" id="name">
<input type="hidden" name="token" id="token" />
<input type="hidden" name="action" id="action" />
<input type="submit" name="submit">
</form>
<script src="https://www.google.com/recaptcha/api.js?render=put your site key here"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
setInterval(function(){
grecaptcha.ready(function() {
grecaptcha.execute('put your site key here', {action: 'application_form'}).then(function(token) {
$('#token').val(token);
$('#action').val('application_form');
});
});
}, 3000);
});
</script>
</body>
</html>
Next, I have created recaptcha.php file to execute it at the server side
<?php
if ($_POST['submit']) {
$name = $_POST['name'];
$token = $_POST['token'];
$action = $_POST['action'];
$curlData = array(
'secret' => 'put your secret key here',
'response' => $token
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($curlData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$curlResponse = curl_exec($ch);
$captchaResponse = json_decode($curlResponse, true);
if ($captchaResponse['success'] == '1' && $captchaResponse['action'] == $action && $captchaResponse['score'] >= 0.5 && $captchaResponse['hostname'] == $_SERVER['SERVER_NAME']) {
echo 'Form Submitted Successfully';
} else {
echo 'You are not a human';
}
}
Source of this code. If you would like to know the explanation of this code please visit. Google reCAPTCHA V3 integration in PHP
For a "basic form" (as the original question asks) what's needed is simple if you're content to validate on the server. Here's a complete HTML page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="https://www.google.com/recaptcha/api.js"></script>
<script>
<!--
function onSubmit() {
var form = document.forms[0];
if ( form['name'].value ) {
form.submit();
} else {
alert( 'Please provide a name.' );
}
}
//-->
</script>
</head>
<body>
<form action="process.asp" method="post">
Name: <input type="text" name="name" /><br /><br />
<button class="g-recaptcha" data-sitekey="SITE_KEY" data-callback='onSubmit' data-action='contact'>Send</button>
</form>
</body>
</html>
And here's the complete page for processing it, using Classic ASP (filename = process.asp) for simplicity:
<%# Language=JavaScript %>
<%
var name = Request( 'name' ).Item;
var recaptchaResponse = Request( 'g-recaptcha-response' ).Item;
var ip = Request.ServerVariables( 'REMOTE_ADDR' );
var xmlhttp = Server.CreateObject( 'MSXML2.ServerXMLHTTP' );
var query = 'secret=SECRET_KEY&response=' + recaptchaResponse + '&remoteip=' + ip;
xmlhttp.open( 'POST', 'https://www.google.com/recaptcha/api/siteverify?' + query, false ); // false says to wait for response
xmlhttp.send();
var response = JSON.parse( xmlhttp.responseText );
Response.Write( name + ' is a ' + (response.success && response.action == 'contact' && response.score > 0.5 ? 'HUMAN' : 'ROBOT') );
%>
A few notes:
You'll supply your own SITE_KEY and SECRET_KEY.
You'll need a JSON parser.
You'll do the server-side POST using a method suitable for your
server.
I added one simple form field validation so you can see how to
integrate that.
You can make the "action" string anything you want, but be sure that
what's on the server is consistent with what's in the HTML.
You might want to respond differently to a response.success that
isn't true or a response.action that doesn't match your action
string, or do other error checking.
You might want a score conditional other than "> 0.5".
This code has no problems with the two-minute timeout.
I process POST on PHP from an angular ajax call. I also like to see the SCORE from google.
This works well for me...
$postData = json_decode(file_get_contents('php://input'), true); //get data sent via post
$captcha = $postData['g-recaptcha-response'];
header('Content-Type: application/json');
if($captcha === ''){
//Do something with error
echo '{ "status" : "bad", "score" : "none"}';
} else {
$secret = 'your-secret-key';
$response = file_get_contents(
"https://www.google.com/recaptcha/api/siteverify?secret=" . $secret . "&response=" . $captcha . "&remoteip=" . $_SERVER['REMOTE_ADDR']
);
// use json_decode to extract json response
$response = json_decode($response);
if ($response->success === false) {
//Do something with error
echo '{ "status" : "bad", "score" : "none"}';
}else if ($response->success==true && $response->score <= 0.5) {
echo '{ "status" : "bad", "score" : "'.$response->score.'"}';
}else {
echo '{ "status" : "ok", "score" : "'.$response->score.'"}';
}
}
On HTML
<input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">
On js
$scope.grabCaptchaV3=function(){
var myCaptcha = angular.element('#g-recaptcha-response').val();
var params = {
method: 'POST',
url: 'api/recaptcha.php',
headers: {
'Content-Type': undefined
},
data: {'g-recaptcha-response' : myCaptcha }
}
$http(params).then(function(result){
console.log(result.data);
}, function(response){
console.log(response.statusText);
});
}
if you are newly implementing recaptcha on your site, I would suggest adding api.js and let google collect behavioral data of your users 1-2 days. It is much fail-safe this way, especially before starting to use score.

Symfony: No route found for "GET/content/articles/changeArt......"

I have a button that contains a link to another page, and pass some variables from the twig template to the controller action of that page :
<button class="btn btn-warning btn-xs" title="modifier l'article">
<i class="fa fa-pencil-square-o"></i>
</button>
The variables pass to the action successfully but I get an error :
No route found for "GET /content/articles/changeArt/3/test3/%3Ci%3E%3Cu%20style=%22background-color:%20rgb%28255,%20255,%200%29;%22%3Esdfghyujhgrertjr%22%5Ekrjthbkrkjgjgrhgiebgfjkebvkebvkezbkzbkdzbdkzbckdszb%20sdnckdzb%20nc,de%3C/u%3E%3C/i%3E/11/04/2017" (from "http://127.0.0.1/PFE_CNAM/web/content/articles")
(the variable 'content' its of type BLOB, and I start geting this error when i changed its type, because before when it was of type text,this action was working pretty good).
Here is the action code :
/**
* #Route("/content/articles/changeArt/{id}/{title}/{content}/{date}",defaults={"id": 0,"title": 0,"content": 0,"date": 0},name="changeArticle")
* #Template()
*/
public function changeArticleAction($id,$title,$content,$date)
{
$session = new Session();
$session->start();
$search = $session->get('user');
$gestAcces = $session->get('acces');
$gestEtat = $session->get('etatUser');
$gestCont = $session->get('contenu');
$repMsg = $session->get('repMsg');
$gestRec = $session->get('Reclam');
$gestMess = $session->get('gestMess');
$gestMp = $session->get('gestMp');
return $this->render('CNAMCMSBundle:Default:changeArticle.html.twig', array('search' => $search,
'contenu' => $gestCont,
'gestAcces' => $gestAcces,
'gestEtat' => $gestEtat,
'repMsg' => $repMsg,
'gestRec' => $gestRec,
'gestMess' => $gestMess,
'gestMp' => $gestMp,
'date'=>$date,
'id'=>$id,
'title'=>$title,
'content'=>$content,
));
}
Look at your route definition /content/articles/changeArt/{id}/{title}/{content}/{date} you can see this route expected exactly 4 params. Then, look at the generated path /content/articles/changeArt/3/test3/%3Ci%3E%3Cu%20style=%22background-color:%20rgb%28255,%20255,%200%29;%22%3Esdfghyujhgrertjr%22%5Ekrjthbkrkjgjgrhgiebgfjkebvkebvkezbkzbkdzbdkzbckdszb%20sdnckdzb%20nc,de%3C/u%3E%3C/i%3E/11/04/2017, it has alot of params separated by / because your params contains slashes.
When matching the URI with route path, it look like:
id: 3
title: test3
content: %3Ci%3E%3Cu%20style=%22background-color:%20rgb%28255,%20255,%200%29;%22%3Esdfghyujhgrertjr%22%5Ekrjthbkrkjgjgrhgiebgfjkebvkebvkezbkzbkdzbdkzbckdszb%20sdnckdzb%20nc,de%3C
date: u%3E%3C
i%3E // how about these extra params?
11 //
04 //
2017 //
I don't known which Symfony version you're using, it should throw exeption if your params contains /. You can solve your problem by encode your params before generate the url.
{{ path('changeArticle', {
id: id,
title: titre|url_encode,
content: corps|url_encode,
date: pub|date('d/m/Y')|url_encode
}) }}
Is 'date':pub|date('d/m/Y') a Typo?
Try this:
<button class="btn btn-warning btn-xs" title="modifier l'article">
<a
href="{{ path('changeArticle',{
'id' : id,
'title' : titre,
'content' : corps,
'date' : date|date('d/m/Y')
}) }}"
style="color: #ffffee;text-decoration: none;"><i class="fa fa-pencil-square-o"></i>
</a>
</button>

Handle two forms in one Controller with Symfony2

Hey I am saving every page in two different languages on my website. I want to manage my pages with an admin area that I am developing with symfony2 at the moment.
Following controller code is able to display two forms on the same page containing the right data from the database. One form to manage the DE language and another for EN:
View:
<form action="{{ path('admin_about') }}" method="post" {{ form_enctype(formEN) }}>
{{ form_widget(formEN) }}
<button type="submit" class="btn btn btn-warning" naem="EN">Save</button>
</form>
<form action="{{ path('admin_about') }}" method="post" {{ form_enctype(formDE) }}>
{{ form_widget(formDE) }}
<button type="submit" class="btn btn btn-warning" name="DE">Save</button>
</form>
Controller:
public function aboutAction(Request $request)
{
$pageEN = $this->getDoctrine()
->getRepository('MySitePublicBundle:Page')
->findOneBy(array('idName' => 'about', 'lang' => 'EN'));
$pageDE = $this->getDoctrine()
->getRepository('MySitePublicBundle:Page')
->findOneBy(array('idName' => 'about', 'lang' => 'DE'));
if (!$pageDE) {
throw $this->createNotFoundException('About page (DE) not found.');
}
if (!$pageEN) {
throw $this->createNotFoundException('About page (EN) not found.');
}
$formDE = $this->createFormBuilder($pageDE)
->add('title', 'text')
->add('content', 'text')
->getForm();
$formEN = $this->createFormBuilder($pageEN)
->add('title', 'text')
->add('content', 'text')
->getForm();
//Save Form here
return $this->render('MySitePublicBundle:Admin:about.html.twig', array(
'aboutPageDE' => $pageDE, 'aboutPageEN' => $pageEN, 'formDE' => $formDE->createView(), 'formEN' => $formEN->createView(),
));
}
My Question is: How to save the form that has been used out of one controller?
Based on the Forms and Doctrine section of the Symfony2 Docs (or in your case, since you're not using a Form class) --
So where you have //save form here assuming you've set up MySitePublicBundle:Page to save the Title and Content (and has the normal getters/setters).
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
// data is an array with "title" and "content" keys
$data = $form->getData();
// You'll need to have some switch depending on which language you're dealing
// with... (unless its both, then just repeat for $pageDE)
$pageEn->setTitle($data['title']);
$pageEn->setContent($data['content']);
$em = $this->getDoctrine()->getEntityManager();
$em->persist($pageEn);
$em->flush();
}
In your controller you could test if the request contains the forms, such as:
if($this->getRequest()->get('form1')) {
//
} elseif($this->getRequest()->get('form2')) {
//
}

collection Field Type not creating form elements

I'm trying to create a form which will add a new text box every time the 'Add new box' link got clicked.
I read through the following example.
http://symfony.com/doc/current/reference/forms/types/collection.html
Basically I was following the example from the book. But when the page is rendered and I click on the link nothing happens.
Any thoughts?
Thanks.
This is my controller.
public function createAction() {
$formBuilder = $this->createFormBuilder();
$formBuilder->add('emails', 'collection', array(
// each item in the array will be an "email" field
'type' => 'email',
'prototype' => true,
'allow_add' => true,
// these options are passed to each "email" type
'options' => array(
'required' => false,
'attr' => array('class' => 'email-box')
),
));
$form = $formBuilder->getForm();
return $this->render('AcmeRecordBundle:Form:create.html.twig', array(
'form' => $form->createView(),
));
}
This is the view.
<form action="..." method="POST" {{ form_enctype(form) }}>
{# store the prototype on the data-prototype attribute #}
<ul id="email-fields-list" data-prototype="{{ form_widget(form.emails.get('prototype')) | e }}">
{% for emailField in form.emails %}
<li>
{{ form_errors(emailField) }}
{{ form_widget(emailField) }}
</li>
{% endfor %}
</ul>
Add another email
</form>
<script type="text/javascript">
// keep track of how many email fields have been rendered
var emailCount = '{{ form.emails | length }}';
jQuery(document).ready(function() {
jQuery('#add-another-email').click(function() {
var emailList = jQuery('#email-fields-list');
// grab the prototype template
var newWidget = emailList.attr('data-prototype');
// replace the "$$name$$" used in the id and name of the prototype
// with a number that's unique to our emails
// end name attribute looks like name="contact[emails][2]"
newWidget = newWidget.replace(/\$\$name\$\$/g, emailCount);
emailCount++;
// create a new list element and add it to our list
var newLi = jQuery('<li></li>').html(newWidget);
newLi.appendTo(jQuery('#email-fields-list'));
return false;
});
})
</script>
This problem can be solved by referring to the following link.
https://github.com/beberlei/AcmePizzaBundle
Here you will find the same functionality being implemented.
I've been through this too.
Answer and examples given to this question and the other question I found did not answer my problem either.
Here is how I did it, in some generic manner.
In generic, I mean, Any collection that I add to the form just need to follow the Form template loop (in a macro, for example) and that's all!
Using which convention
HTML is from Twitter Bootstrap 2.0.x
Javascript code is already in a $(document).ready();
Following Symfony 2.0.x tutorial
Using MopaBootstrapBundle
Form Type class
class OrderForm extends AbstractType
{
// ...
public function buildForm(FormBuilder $builder, array $options)
{
// ...
$builder
->add('sharingusers', 'collection', array(
'type' => new UserForm(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'required'=> false
));
// ...
}
}
JavaScript
/* In the functions section out of document ready */
/**
* Add a new row in a form Collection
*
* Difference from source is that I use Bootstrap convention
* to get the part we are interrested in, the input tag itself and not
* create a new .collection-field block inside the original.
*
* Source: http://symfony.com/doc/current/cookbook/form/form_collections.html
*/
function addTagForm(collectionHolder, newBtn) {
var prototype = collectionHolder.attr('data-prototype');
var p = prototype.replace(/\$\$name\$\$/g, collectionHolder.children().length);
var newFormFromPrototype = $(p);
var buildup = newFormFromPrototype.find(".controls input");
var collectionField = $('<div class="collection-field"></div>').append(buildup);
newBtn.before(collectionField);
}
/* ********** */
$(document).ready(function(){
/* other initializations */
/**
* Form collection behavior
*
* Inspired, but refactored to be re-usable from Source defined below
*
* Source: http://symfony.com/doc/current/cookbook/form/form_collections.html
*/
var formCollectionObj = $('form .behavior-collection');
if(formCollectionObj.length >= 1){
console.log('run.js: document ready "form .behavior-collection" applied on '+formCollectionObj.length+' elements');
var addTagLink = $('<i class="icon-plus-sign"></i> Add');
var newBtn = $('<div class="collection-add"></div>').append(addTagLink);
formCollectionObj.append(newBtn);
addTagLink.on('click', function(e) {
e.preventDefault();
addTagForm(formCollectionObj, newBtn);
});
}
/* other initializations */
});
The form template
Trick here is that I would have had used the original {{ form_widget(form }} but I needed to add some specific to the view form and I could not make it shorter.
And I tried to edit only the targeted field and found out it was a bit complex
Here is how I did it:
{# All form elements prior to the targeted field #}
<div class="control-collection control-group">
<label class="control-label">{{ form_label(form.sharingusers) }}</label>
<div class="controls behavior-collection" data-prototype="{{ form_widget(form.sharingusers.get('prototype'))|escape }}">
{% for user in form.sharingusers %}
{{ form_row(user) }}
{% endfor %}
</div>
</div>
{{ form_rest(form) }}

Symfony2: entity field (html SELECT) set SELECTED item

I am using a form (filterForm) to filter entities on a twig view.
The 'filterForm' only has a field of 'entity' type. On the view it shows a HTML-SELECT-OPTIONs tag.
When the user changes the selection, the same controller is called doing the neccesary stuff to filter the entities-list.
All is working fine but I need to show the SELECT-field with the value that is filtering the list. And here is the problem, I don't know how to do it.
A bit of code of the field from the index.html.twig:
{{ form_widget(personalFilterForm.personaFiltrarMail,
{ 'empty_value': 'Todos',
'attr': {'selected': personaFiltrarMail,
'onChange': 'javascript:document.filtrado.submit()' }
}
)
}}
That code is generating this html code:
<select name="test_onebundle_type[personaFiltrarMail]" id="test_onebundle_type_personaFiltrarMail"
onchange="javascript:document.filtrado.submit()"
required="required" selected="two#mail.com">
<option value="">Todos</option>
<option value=one#mail.com">Name One</option>
<option value=two#mail.com">Name Two</option>
<option value=three#mail.com">Name three</option>
The real problem here (I think) is knowing how can I get access to the OPTIONS sub-element to set de SELECTED attribute on a concrete OPTION item.
Thanks.
=== Controller ===
Here the 'Controller'...
All four numbered 'echoes' gives me the mail: 'two#mail.com' But the SELECT html TAG is always located on the first one OPTION tag.
class HorasController extends Controller
{
/**
* Lists all Horas entities.
*
* #Route("/", name="horas")
* #Template()
*/
public function indexAction()
{
$em = $this->getDoctrine()->getEntityManager();
$personas = $em->getRepository('PtGhorgaBundle:Personal')->findAll();
$personalFilterForm = $this->createForm(new PersonalFilterType(), $personas);
$request = $this->getRequest();
$formVars = $request->request->get('pt_ghorgabundle_type');
$personaFiltrarMail = $formVars['personaFiltrarMail'];
//echo "1.- [".$personaFiltrarMail."]<br />";
if (!isset($personaFiltrarMail) || $personaFiltrarMail=="") {
$entities = $em->getRepository('PtGhorgaBundle:Horas')->findAll();
} else {
$criterio = array('persona' => $personaFiltrarMail,);
$entities = $em->getRepository('PtGhorgaBundle:Horas')->findBy($criterio);
$criterio = array('mail' => $personaFiltrarMail,);
$personaFiltrarMail = $em->getRepository('PtGhorgaBundle:Personal')->find($criterio)->getMail();
echo "2.- [".$personaFiltrarMail."]<br />";
$personalFilterForm->personaFiltrarMail = $personaFiltrarMail;
echo "3.- [".$personaFiltrarMail."]<br />";
echo "4.- [".$personalFilterForm->personaFiltrarMail."]<br />";
}
return array('entities' => $entities,
'personas' => $personas,
'personalFilterForm' => $personalFilterForm->createView(),
'personaFiltrarMail' => $personaFiltrarMail,
);
}
In your data you can set the property personaFiltrarMail to the according value.
For example in your controller :
$object = new Object();
$object->personaFiltrarMail = 'two#mail.com';
$form = $this->createFormBuilder($object);
Then render your template.
I have found it:
just belown
echo "4....." line
$data = array('personaFiltrarMail'=> $personaFiltrarMail);
$personalFilterForm->setData($data);
Regards.

Resources