ZF2 - Separating one form in many tabs - php

I need a help..
I have a unique form with multiples fieldsets, and i need separate some fieldsets in tabs..
So, i tried in the view (form is my variable with the whole form):
$form = $this->form;
$customFieldset = $form->get('customFieldset');
$form->remove('customFieldset');
It works, my fieldset form is in $customFieldset.. but, i can't render this!
When a try:
echo $this->form($customFieldset);
//OR
echo $this->formInput($customFieldset);
//OR
$this->formCollection($customFieldset);
None of that works..
I'm doing right? How i can do it?
Thank very much.

To achieve the result you want (using the form across several tabs, it is better to construct the form differently, based on the tab's number. For example, your form constructor method would look like below:
<?php
namespace Application\Form;
use Zend\Form\Form;
// A form model
class YourForm extends Form
{
// Constructor.
public function __construct($tabNum)
{
// Define form name
parent::__construct('contact-form');
// Set POST method for this form
$this->setAttribute('method', 'post');
// Create the form fields here ...
if($tabNum==1) {
// Add fields for the first tab
} else if($tabNum==2) {
// Add fields for the second tab
}
}
}
In the example above, you pass the $tabNum parameter to form model's constructor, and the constructor method creates a different set of fields based on its value.
In your controller's action, you use the form model as below:
<?php
namespace Application\Controller;
use Application\Form\ContactForm;
// ...
class IndexController extends AbstractActionController {
// This action displays the form
public function someAction() {
// Get tab number from POST
$tabNum = $this->params()->fromPost('tab_num', 1);
// Create the form
$form = new YourForm($tabNum);
// Check if user has submitted the form
if($this->getRequest()->isPost()) {
// Fill in the form with POST data
$data = $this->params()->fromPost();
$form->setData($data);
// Validate form
if($form->isValid()) {
// Get filtered and validated data
$data = $form->getData();
// ... Do something with the validated data ...
// If all tabs were shown, redirect the user to Thank You page
if($tabNum==2) {
// Redirect to "Thank You" page
return $this->redirect()->toRoute('application/default',
array('controller'=>'index', 'action'=>'thankYou'));
}
}
}
// Pass form variable to view
return new ViewModel(array(
'form' => $form,
'tabNum' => $tabNum
));
}
}
In your view template, you use the following code:
<form action="">
<hidden name="tab_num" value="<?php echo $this->tabNum++; ?>" />
<!-- add other form fields here -->
</form>

Related

Set collection according to property value and update via AJAX

I have an email object which contains a collection textareas and has a property template. The collection textareas contains the textareas in template, which are set in the controller.
public function editAction($id, Request $request)
{
// Get the email
$email = EmailQuery::create()->findPk($id);
if (!$email)
{
throw $this->createNotFoundException('Unknown email ID.');
}
// If a new template file is selected, the client refreshes the form with ajax
// So let's get the new template value
if (isset($request->request->get('email')['template']))
{
if (isset($request->request->get('email')['update_with_ajax']))
$email->setTemplate($request->request->get('email')['template']);
}
// Get textareas in the email's template
$email->setTextareas($this->get('email.analyzer')->getTextAreas($email->getTemplate()));
// Create form
$form = $this->createForm('email', $email);
// Handle form
$form->handleRequest($request);
if ($form->isValid() && $form->get('save')->isClicked())
{
$form->save();
}
}
This is my email type (which is a service):
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class EmailType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Read template files in dir and store names in $templates
// $templates = array();
$builder->add('template', 'choice', array('choices' => $templates);
$builder->add('textareas', 'collection');
$builder->add('save', 'submit');
$builder->add('update_with_ajax', 'submit');
}
}
The problem here is that I want to update the textareas collection via AJAX when the user chooses another template. As you can see I add the collection of templates to the email object before creating the form, I think that's where it all goes wrong and triggers the This form should not contain extra fields error. But what is the right approach?

Yii - updating a model and using the model to echo data in the view

I have the following code for updating a Yii model:
public function actionSettings($id) {
if (!isset($_POST['save_hostname']) && isset($_POST['Camera']) && isset($_POST['Camera']['hostname'])) {
$_POST['Camera']['hostname'] = '';
}
$model = $this->loadModel($id);
$model->setScenario('frontend');
$this->performAjaxValidation($model);
if (isset($_POST['Camera'])) {
$model->attributes = $_POST['Camera'];
unset($model->api_password);
if ($model->save()) {
Yii::app()->user->setFlash('success', "Camera settings has been saved!");
} else {
Yii::app()->user->setFlash('error', "Unable to save camera settings!");
}
}
$this->render('settings', array(
'model' => $model,
));
}
This works fine, except in my model I have code like this:
<h1>Settings For: <?php echo CHtml::encode($model->name); ?></h1>
The problem is that, even when the user input fails validation, the h1 tag is having bad input echoed out into it. If the input fails the validation, the h1 attribute should stay the same.
I can 'reset' the $model variable to what is in the database before the view is returned, but this then means I don't get any error feedback / validation failed messages.
Is my only option to have 2 $models ($model and $data perhaps), one used for handling the form and the other for sending data to the page? Or does someone have a more elegant solution?
performAjaxValidation assigns all save attributes to the model so this behavior is normal.
I would reload model if save fails.
$model->refresh();

How to pass variable from action to form

I am sure I am going about this the wrong way, but I need to unset an array key from one of my choices in a sfWidgetFormChoice. The only way to get that variable to the Form is from the action. Here's what I have:
Action:
$id = $request->getParameter('id');
$deleteForm = new UserDeleteForm();
$choices = array();
$choices = $deleteForm->getWidgetSchema('user')->getAttribute('choices');
unset($choices[$id]); //I obviously don't want the user to be able to transfer to the user being deleted
$this->deleteForm = $deleteForm;
Form:
$users = Doctrine_Core::getTable('sfGuardUser')->getAllCorpUsers()->execute();
$names = array();
foreach($users as $userValue){
$names[$userValue->getId()] = $userValue->getProfile()->getFullName();
};
// unset($names[$id]); //this works, but I can't figure out how to get $id here.
$this->widgetSchema['user'] = new sfWidgetFormChoice(array(
'choices' => $names
));
$this->validatorSchema['user'] = new sfValidatorChoice(array(
'required' => true,
'choices' => $names
));
Understanding forms and actions:
Usually we will setup a form with fields, print it in a html page and fill the form with data. Pressing the submit form button will send all the data to a method defined in your form action html attribute.
The method will receive and get a $request , with a lot of parameters and also the form with the data. Those values will be processed in the action.
Lets look how it exactly works in symfony:
Define and Setup a symfony form, like the one you have shown above.
Print the form and in the action parameter point to the submit method
which will receive the request:
<form action="currentModuleName/update"
Symfony will automatically send the request to the action.class.php
of your module, and will look for and send the data to the function
executeUpdate
public function executeUpdate(sfWebRequest $request){ //...
$this->form = new TestForm($doctrine_record_found);
$this->processForm($request, $this->form); }
After some checks, symfony will process the form and set a result
template.
processForm(sfWebRequest $request, sfForm $form)
{ ... } $this->setTemplate('edit');
In the processForm of your module action.class.php, you should process all the received values (request) also with the form:
protected function processForm(sfWebRequest $request, sfForm $form)
{
$form->bind($request->getParameter($form->getName()), $request->getFiles($form->getName()));
if ($form->isValid())
{
$formValues = $this->form->getValues();
$Id = $formValues['yourWidgetName'];
}
}
You may check the following link for an example like yours, about how to process a sfWidgetFormChoice.
And now answering to the real question, in order to select the deleted users, add the following code in your action:
//process the form, bind and validate it, then get the values.
$formValues = form->getValues();
$choicesId = $formValues['choices'];
Pass variable from action to the form:
Excuse me if I have not understand your question at all but in case you need to pass some parameters from your action to the form, send the initialization variables in an array to the form constructor:
Pass a variable to a Symfony Form
In your case, get the list of users, delete the user you dont want and send the non deleted users to the form constructor.
You will need to redeclare/overwrite your form again in the configure() function so that you could change the initialization of the form. Copy and paste the same code into the configure() function and comment the line: //parent::setup();
class TbTestForm extends BaseTbTestForm
{
public function configure()
{
//.. copy here the code from BaseTbTestForm
//parent::setup();
$vusers = $this->getOption('array_nondeleted_users');
//now set the widget values with the updated user array.
}
}

Symfony submit to same url

I have a form with some text fields and I have a preview button that needs to submit the form to the same controller. And then in the controller, I need to extract the values and populate a form with these values for the template to see. What is the best way to achieve this? I'm a newbe so please be clear.
Sample controller:
public function myControllerName(sfWebRequest $request)
{
$this->form = new myFormClass();
}
Use <?php echo $form->renderFormTag( url_for('#yourRoutingName'), array('method' => 'POST') ); ?> in your template and change #yourRoutingName to the one pointing to your controller.
Now change your controller to be something like this:
public function myControllerName(sfWebRequest $request)
{
$this->form = new myFormClass();
if ($request->isMethod(sfRequest::POST)
{
$this->form->bind( $request->getParameter( $this->form->getName() ) );
// Check if the form is valid.
if ($this->form->isValid())
{
$this->form->save();
// More logic here.
}
}
}
The $this->form->bind( $request->getParameter( $this->form->getName() ) ); part binds posted data to your form where $this->form->isValid() returns a boolean whether the form is valid or not.
Have you tried this ?
$this->redirect($request->getReferer()); //action
if not, then please try and check if its work for you.
Thanks.

Can I direct two different buttons to the same function in a controller with the same view in CakePHP?

There are two buttons in my cakephp page,one for registering new users and the other one for login. Can both the button's action be directed to the same function in the controller and have the same view.ctp file? If yes, how can I do it?
Yes, just set the correct URL in your buttons. But I don't know why you would do this. If it is just about re-using the view.ctp then you do not need to use a single action just to use the same view. Example:
<?php
class FoobarController extends AppController
{
function view()
{
// This will render views/foobar/view.ctp because the action
// is named "view"
}
function register()
{
// Normally this would render views/foobar/register.ctp but you can
// call the render() function manually and render something else. The
// following call will render views/foobar/view.ctp
$this->render('view');
}
function login()
{
// Same thing here...
$this->render('view');
}
}
?>
I create buttons in my CRUD admin pages that allow either "Confirm (edit/delete/create/etc)" or "Cancel". I do this by creating 2 submit buttons in the form, and giving each a unique name. For example:
View code:
...
$form->submit('Delete', array('name' => 'delete'));
$form->submit('Cancel', array('name' => 'cancel'));
...
Action logic:
function admin_delete( ... ) {
// Bail if cancel button pressed
if (isset($this->params['form']['cancel'])) {
$this->redirect('/');
}
// Delete if delete button pressed
if (isset($this->params['form']['delete'])) {
// delete stuff
...
}
...
}
On the flip side, you're essentially smashing 2 actions into one for the sake of reusing a view. Sander Marechal's solution is better.
Well, yes, why not? Isn't this only a matter of setting the appropriate URL in your form actions? Or am I missing something?
You can use a hidden form value to denote which action it is.
$form->create('User', array('action' => 'process');
$form->hidden('User.signup', array('value' => '1'));
$form->end('Signup');
$form->create('User', array('action' => 'process');
$form->hidden('User.login', array('value' => '1'));
$form->end('Login');
It isn't exactly clear why you don't want to use 2 functions though. You are basically going to have to manually check which action it is, instead of letting cake do it for you.
In your controller
function process()
{
if ($this->data['User']['signup'] == 1)
{
// process signup
}
if ($this->data['User']['login'] == 1)
{
// process login
}
}

Categories