I am trying to create a form whose structure depends on the parameter in the url. If no parameter is specified in the url, an error message should be displayed. Depending on the id, a database query is performed and the form is filled with data.
example url: http://127.0.0.1/local/group/signin.php?groupid=14
Unfortunately, my form doesn't validate after I submit the form via pressing the action button. It jumps to http://127.0.0.1/local/group/signin.php and because there is no parameter present in the url the error message 'No group found' is displayed.
What have I done wrong here?
signinform.php:
class signinform extends moodleform {
public function definition() {
global $DB;
global $USER;
$mform = $this->_form;
$urlid = $this->_customdata['id']; // get the passed group id
$message = 'No group found';
if(is_null($urlid)){
$mform->addElement('html', '<h3>'.\core\notification::error($message).'</h3>');
}
else{
// build the form, sql query etc.
$this->add_action_buttons(true, 'Submit');
}
}
function validation($data, $files) {
return array();
}
}
signin.php:
$PAGE->set_url(new moodle_url('/local/schedule/signin.php?'));
$PAGE->set_context(\context_system::instance());
$PAGE->set_pagelayout('base');
$PAGE->set_title("Sign up");
$PAGE->set_heading("Sign up for a group");
global $DB;
global $USER;
$urlid = $_GET["id"];
$to_form = array('id' => $urlid); // pass group id to form
$mform = new signinform(null, $to_form);
$homeurl = new moodle_url('/');
if ($mform->is_cancelled()) {
redirect($homeurl, 'Cancelled.'); // Just for testing, never enters here
} else if ($fromform = $mform->get_data()) {
redirect($homeurl, 'Validation in process'); // Just for testing, never enters here
}
echo $OUTPUT->header();
$mform->display();
echo $OUTPUT->footer();
You need to add a hidden field to the form that contains the 'id' that has to be passed to the page, otherwise, when the form is submitted, that id will no longer be present in the params for that page.
e.g. (in definition())
$mform->addElement('hidden', 'id', $urlid);
$mform->setType('id', PARAM_INT);
Also, in Moodle, you should never access $_GET directly - use the wrapper functions required_param() or optional_param(), as these:
Clean the parameter to the declared type
Automatically take parameters from either $_GET or $_POST (which will be important in this case, as the 'id' param will be part of the POST data, when you submit the form)
Handle missing parameters by either applying a default (optional_param) or stopping with an error message (required_param)
So your access to $_GET['id'], should be replaced with:
$urlid = optional_param('id', null, PARAM_INT);
Related
I'm verifying a form input and making sure the user doesn't submit the form twice. I'm doing this with the following class:
<?php
//You can of course choose any name for your class or integrate it in something like a functions or base class
class formKey
{
//Here we store the generated form key
private $formKey;
//Here we store the old form key (more info at step 4)
private $old_formKey;
//The constructor stores the form key (if one excists) in our class variable
function __construct()
{
//We need the previous key so we store it
if(isset($_SESSION['form_key']))
{
$this->old_formKey = $_SESSION['form_key'];
}
}
//Function to generate the form key
private function generateKey()
{
//Get the IP-address of the user
$ip = $_SERVER['REMOTE_ADDR'];
//We use mt_rand() instead of rand() because it is better for generating random numbers.
//We use 'true' to get a longer string.
//See http://www.php.net/mt_rand for a precise description of the function and more examples.
$uniqid = uniqid(mt_rand(), true);
//Return the hash
return md5($ip . $uniqid);
}
//Function to output the form key
public function outputKey()
{
//Generate the key and store it inside the class
$this->formKey = $this->generateKey();
//Store the form key in the session
$_SESSION['form_key'] = $this->formKey;
//Output the form key
echo "<input type='hidden' name='form_key' id='form_key' value='".$this->formKey."' />";
}
//Function that validated the form key POST data
public function validate()
{
//We use the old formKey and not the new generated version
if($_POST['form_key'] == $this->old_formKey)
{
//The key is valid, return true.
unset($_SESSION['form_key']);
return true;
}
else
{
//The key is invalid, return false.
return false;
}
}
}
?>
This is output to the form like this then:
include STYLESHEETPATH . '/formkey.class.php';
$formKey = new formKey();
$formKey->outputKey();
If I echo out the old_formKey and the post form_key they are the exact same and it works in every browser other than Safari. If I check these in Safari, the old_formKey is always different. Why would this be?
I am attempting to set the "title" value of a content type before it becomes "required" .
So what happens is the title field becomes hidden based on user name, after filling in the "first name" and "last name" fields I need to take those values and then apply them to the "title" field, before drupal states that the field is required. Here's what I have so far
/**
* Implements hook_form_alter().
*/
function editorhide_form_alter(&$form, &$form_state, $form_id){
global $user;
global $fullTitle;
if($form_id == 'artist_node_form'){
if( $user->name == 'Editor'){
drupal_add_js("jQuery(document).ready(function(){
jQuery('#edit-title').hide();
});","inline");
//adding the form handler
$form['#submit'][] = "editorhide_form_submit_handler";
}
}
}
//submit form handler.
function editorhide_form_submit_handler ($form, &$form_state) {
global $fullTitle;
$fullTitle = $form_state['values']['field_firstname']['und']['0']['value'];
$fullTitle .= ' '. $form_state['values']['field_lastname']['und']['0']['value'];
form_set_value($form['#edit-title'], $fullTitle,$form_state);
}
With my current implementation, it isn't doing quite what I want, as it's throwing the "required field" error.
The problem you are having is that your new submit function never gets executed. A form will go through all validation functions first.
You need to set a new validate function, and make sure it is inserted at the begining of the validation process (so you can set title prior to the node validation):
array_unshift($form['#validate'], "editorhide_form_validate_handler");
Then your validation can do the following (may need to adjust array indexes):
function editorhide_form_validate_handler ($form, &$form_state) {
$fullTitle = $form_state['values']['field_firstname']['und']['0']['value'];
$fullTitle .= ' '. $form_state['values']['field_lastname']['und']['0']['value'];
$form_state['values']['title']['und']['0']['value'] = $fullTitle;
}
I am not a HUGE fan of modifying form_state mid validation, but this should work.
I am trying to submit a EDIT form which edits Users Academics Details,
These Details have unique id in DB and my Code in Short Looks like below :
class edit extends ci_controller
{
function user_academics($id = NULL)
{
if(isset($id) == FALSE) //if link is ./edit/user_academics
{
$id = NULL;
$link = site_url('profile');
show_error("Invalid Page Request! <a href='$link' Go to Profile </a>");
}
$user_id = $this->session->userdata('user_id');
$data['fill'] = $this->edit_model->get_user_academics($id);
if($user_id != $data['fill']['user_id']) // check if logged in user is accessing his record or others
{
$link = site_url('profile');
show_error("This is an Invalid Request ! <a href='$link'>Go to Profile </a>");
}
else // actual work starts here
{
$this->session->set_flashdata('ua_id',$id); // update_academics will get this data
$this->load->view('edit/edit_3_view',$data);
}
}
function update_academics()
{
$ua_id = $this->session->flashdata('ua_id'); // flash data used here .
if( !$ua_id )
{
show_error('Sorry, This request is not valid!');
}
$academics = array(
// All post values
);
$this->edit_model->update_user_academics($academics,$ua_id);
//print_r($academics);
redirect('profile');
}
}
Now the problem is
- If I open two different records to edit, then It will set only one Session Flash value.
- And No matter what I edit , the existing values of the last flash value gets updated.
Please Suggest me another way or Correct me if I am wrong in above code . Thanks
save that flashdata in array, like:
$myArr = array('value 1', 'value 1');
//set it
$this->session->set_flashdata('some_name', $myArr);
And in view:
$dataArrs = $this->session->flashdata('some_name');
//loop thru $dataArrs to show the flashdata
Flash data is simply like variable which is available only in next request, you can bypass this behavior by using two different keys with record id in it, so that when you use flash data for showing message you can access key with particular record id.
I am having one dropdown option in the form called town. Already fetched values will be available in drop down from the databasetable townId. Now I want to check if the user doesn't select any choice from the dropdown and directly goes to the save button, then it should display "please choose your choice in dropdown" like that. The form is named university
I tried this code here:
if(Zend_Form_Element_Submit)
{
if($$townid=='')
{ alert("U Must Choose Town Name Here");
}
else
{
$submit = new Zend_Form_Element_Submit('Save');
$submit->setDecorators($this->submitDecorators)
->setAttrib('class','button slategray');
}
}
Inside models->university.php there are some actions for dropdown I didn't get exactly:
public function setOptions(array $options)
{
$methods = get_class_methods($this);
foreach ($options as $key => $value) {
$method = 'set' . ucfirst($key);
if (in_array($method, $methods)) {
$this->$method($value);
}
}
return $this;
}
Before I edited form->university (the save code already exits)
$submit = new Zend_Form_Element_Submit('Save');
$submit->setDecorators($this->submitDecorators)
->setAttrib('class','button slategray');
}
Thanks in advance.
To work properly with Zend Framework's forms I recommand to try this approach:
Create a form by extending the Zend_Form class
class Form_User extends Zend_Form
Which automatically give you access to a container to manage all your elements from this form and give you acces to a isValid() method which allow you to validate all your form elements at once and to a populate() method which allow you to feed data to your form for editing
In your new class (Form_User) you can define all your form properties and elements in the init() method.
public function init()
{
$this->setName('user')
->setAttrib('id', 'user');
$username = new Zend_Form_Element_Text('username');
$town = new Zend_Form_Element_Select('town');
$town->addMultioptions(array(...));
$submit = new Zend_Form_Element_Select('submit');
$this->addElements(array($username, $town, $submit));
}
Each of these elements can be customized with a label, a description, some validators, some filters, etc.
If you want to make an element mandatory you can set the Required property to true
$town->setRequired(true);
To validate your form after the submit has been cliqued, you can do it as simply as (assuming you do this in the controller) :
$form = new Form_User();
$postData = $this->getRequest()->getPost();
$form->isValid($postData);
This will check for the required fields as well as execute any validators that you have setted on these diverses elements.
It will return true if everything is ok, and false if there is an error. If you get an error a display the form again, error messages will be shown automatically beside each erroneous fields.
If you want to set options values of your form elements, when you initialize your form, you can pass a configuration array like this :
$form = new Form_User(array('townListOptions' => array(...));
The associated method setTownListOptions will be called automatically and will receive the array (or any other object) you assigned it with.
I could explain even further things about forms but as #Rohan stated in his comment, RTM
In asp.net
<asp:DropDownList ID="ddlusertype" runat="server" CssClass="dropdown" ></asp:DropDownList>
<asp:CompareValidator ID="CompareValidator2" runat="server" ControlToValidate="ddlusertype" ErrorMessage="select" Font-Size="XX-Small" Operator="NotEqual" Type="Integer" ValueToCompare="0"></asp:CompareValidator>
I have following action to display a form
public function showformAction() {
$this->view->form = new Form_MyForm();
$this->view->form->setAction( 'submitform' );
}
above action shows a form successfully with only one textarea and submit button.
And I am using following action to submit above form:
public function submitformAction() {
$form = new Form_MyForm();
$request = $this->getRequest();
if ( $request->isPost() ) {
$values = $form->getValues();
print_r($values);die();
} else {
echo 'Invalid Form';
}
}
Above action is showing following output:
Array ( [myfield] => )
It means it is not posting values correctly and always shows empty array or I am not getting posted values correctly. How to post values to submitformAction().
Thanks
I think you must use the isValid() before accessing the values of a submitted form, because it's right there that the values are checked and valorized
public function submitformAction() {
$form = new Form_MyForm();
$request = $this->getRequest();
if ( $request->isPost() ) {
if ($form->isValid( $request->getPost() )) {
$values = $form->getValues();
print_r($values);die();
}
} else {
echo 'Invalid Form';
}
}
In complement to #VAShhh response. With some more details:
You need to do two things, populate your form fields with the POSTed data and applying security filters and validators to that data. Zend_Form provides one simple function which perform both, it's isValid($data).
So you should:
build your form
test you are in a POST request
populate & filter & validate this data
either handle the fact in can be invalid and re-show the form wich is now
decorated with Errors OR retrieve valid data from the form
So you should get:
function submitformAction() {
$form = new Form_MyForm();
$request = $this->getRequest();
if ( $request->isPost() ) {
if (!$form->isValid($request->getPost())) {
$this->view->form = $form;
// here maybe you could connect to the same view script as your first action
// another solution is to use only one action for showform & submitform actions
// and detect the fact it's not a post to do the showform part
} else {
// values are secure if filters are on each form element
// and they are valid if all validators are set
$securizedvalues = $form->getValues();
// temporary debug
print_r($securizedvalues);die();
// here the nice thing to do at the end, after the job is quite
// certainly a REDIRECT with a code 303 (Redirect after POSt)
$redirector = $this->_helper->getHelper('Redirector');
$redirector->setCode(303)
->setExit(true)
->setGotoSimple('newaction','acontroller','amodule');
$redirector->redirectAndExit();
} else {
throw new Zend_Exception('Invalid Method');
}
}
And as said in the code re-showing the form you shoudl really try to use the same function for both showing and handling POST as a lot of steps are really the same:
building the form
showing it in the view in case of errors
By detecting the request is a POST you can detect you are in the POST handling case.