Render each choice as a row in a table in a Symfony choice widget - forms

I have a sfWidgetFormChoice which renders checkboxes in Symfony 1.4. The problem I have is that I want to rend each choice as a row in a table. So my html would ideally be something like this:
<tr><td>Choice 1</td></tr>
<tr><td>Choice 1</td></tr>
<tr><td>Choice 1</td></tr>
.
.
.
So that it would render as a table instead of a list.
Thanks!

In your form called MyForm create the following widget:
$this->widgetSchema ['my_widget'] = new sfWidgetFormChoice(array('multiple' => true, 'expanded' => true, 'choices' => my_choices, 'renderer_class' => 'sfWidgetFormSelectCheckbox', 'renderer_options' => array('formatter' => array('MyForm', 'MyFormatter'))));
$this->validatorSchema ['my_widget'] = new sfValidatorChoice(array('multiple' => true, 'choices' => array_keys(my_choices), 'required' => false));
Then add the following formatter method called MyFormatter:
public static function MyFormatter($widget, $inputs) {
$result = '<table>';
foreach ($inputs as $input) {
$result .= '<tr><td>' . $input ['label'] . ' ' . $input ['input'] . '</td></tr>';
}
$result .= '</table>';
return $result;
}
I used for choices to be rendered as checkboxes by setting renderer_class option to sfWidgetFormSelectCheckbox in widget definition you can use sfWidgetFormSelectRadio to render it to radio buttons and you can call another formatter from another form by changing array('formatter' => array('MyForm', 'MyFormatter')).

Related

Gravityview - Show payment status of another form

I currently have Gravityview view which is getting the source from form A. However, I want to show if the current user has made a payment on form B. Obviously this can be fetched from the {payment_status} merge tag of form B. But How can I pull the data of form B onto the Gravity view custom content field of form A?
I've looked at the gform_entry_id_pre_save_lead hook but I think there's a better way. Thanks for your help in advance..
add_filter( 'gform_entry_id_pre_save_lead', 'my_update_entry_on_form_submission', 10, 2 );
function my_update_entry_on_form_submission( $entry_id, $form ) {
$update_entry_id = rgpost( 'my_update_entry_id' );
return $update_entry_id ? $update_entry_id : $entry_id;
}
You can either use the Gravityview Multiple Forms Add-on or you can try adding the following code to your functions.php:
function gf_check_form($atts = array()) {
$details = shortcode_atts( array(
'form_id' => "",
'user' => ""
), $atts );
$form_id = $details['form_id'];
$search_criteria = array(
'status' => 'active',
'field_filters' => array(
'mode' => 'all',
array(
'key' => 'created_by',
'operator'=> 'is',
'value' => $details['user']
)
)
);
$entries = GFAPI::get_entries( $form_id, $search_criteria);
foreach($entries as $entry){
$paid .= 'Paid on '.date("F d, Y", strtotime($entry['date_created'])).'<br><br>';
}
return $paid;
}
add_shortcode( 'check_form', 'gf_check_form' );
You can then add the following shortcode to your Gravityview in a custom content field:
[check_form form_id="Add the form ID of form B here" user="{created_by:ID}"]

Yii2 remember sort option after submit the searchForm

I use an ActiveForm in Yii2 for my SearchModel. After click on search button the form fields remember previous values but SorterDropdown is refreshed.
<?php echo SorterDropdown::widget(['sort' => $dataProvider->sort,
'label' => $model->sortedBy($dataProvider->sort->attributes),])
?>
SorterDropdown is just a wrapper of ButtonDropdown.
How can I forse the SorterDropdown to remember sort order (and show it) after the form submition?
class SorterDropdown extends LinkSorter
{
public $label;
protected function renderSortLinks()
{
$attributes = empty($this->attributes) ? array_keys($this->sort->attributes) : $this->attributes;
$links = [];
foreach ($attributes as $name) {
$links[] = Html::tag('li', $this->sort->link($name, ['tabindex' => '-1']));
}
if (empty($this->label))
$this->label = 'Sort';
return \yii\bootstrap\ButtonDropdown::widget([
'encodeLabel' => false,
'label' => $this->label,
'dropdown' => [
'items' => $links,
],
]);
}
You should add some class to li element, which indicate active state of it and special style in CSS file.

ZEND form elements in a table containing also data from the database

Hi there:) i've got a problem with decorators and form which would be in table and in this table want to have also data from database... I dont have any idea how to do this to have a structure like something below, lets say
<table>
<tr>
<td><?php echo array[0]['name']?>
//and here input from zend form
<td>
<select name='foo' id='bar'>
<option value='something'>Foo</option>
<option value='something2'>Foo2</option>
</select>
</td>
</tr>
</table>
Ofcourse tr will be more and generated with foreach or some loop.
I have something like this:
<?php
class EditArticles_Form_EditArticles extends Zend_Form
{
protected $uid;
public function render()
{
/* Form Elements & Other Definitions Here ... */
$this->setName('editarticles');
$data = new EditArticles_Model_DbTable_EditArticlesModel();
$datadata = $data->GetArticlesToEdit($this->getUid()); //here is my data from db
for ($i=0;$i<count($datadata);$i++)
{
$do = new Zend_Form_Element_Select(''.$i);
$do->addMultiOption('0', 'Aktywny');
$do->addMultiOption('1', 'Nieaktywny');
$this->addElements(array($do));
}
$submit = new Zend_Form_Element_Submit('updateart');
$this->addElement($submit);
//and here are decorators for array, and i would like to have in this table also data from array containing data from database
$this->addDecorators(array(
'FormElements',
array('HtmlTag', array('tag' => 'table', 'id' => 'aaaa', 'style' => 'width:500px;')), 'Form',
));
$this->setElementDecorators(array(
'ViewHelper',
array( array('data' => 'HtmlTag'), array('tag' => 'td', 'style' => 'width:200px;')),
array('Label', array('tag' => 'td')),
array(array('row' => 'HtmlTag'), array('tag' => 'tr'))
),
//wykluczenie submita z overrida stulu
array('submit'), false);
return parent::render();
}
//setting user id for get content from db
public function setUid($uid) {
$this->uid = $uid;
return $this;
}
public function getUid() {
return $this->uid;
}
}
?>
output of code above is something like this: (in red marked where i would like to have that selects from form. In this image the table with data is an other table generated in phtml, but i would like to generate that table by form od just insert only the form elements to that table generated in phtml view).
http://img14.imageshack.us/img14/9973/clipboard01pw.png
Something found here:
Zend_Form: Database records in HTML table with checkboxes
but i dont know how to start with that...
Several comments:
Typically, adding elements to the form is done in init(), rather than render().
If a consumer object (this is this case, the form) needs a dependency (in this case, the article model) to do its work, it is often helpful to explicitly provide the dependency to the consumer, either in the consumer's constructor or via setter method (ex: $form->setArticleModel($model)). This makes it easier to mock the model when testing the form and clearly illustrates the form's dependence on the model.
Re: rendering other content in the form via decorators: Maybe, take a look at the AnyMarkup decorator. It looks like (sorry, can't fully understand the Polish) you want a select box on each row you output. So, you get your rows using the model, loop through the rows, creating your select box on each row. When you assign decorators to the select element - ViewHelper, Errors, probably an HtmlTag decorator to wrap it in a <td> - you also add the AnyMarkup decorator to prepend the a bunch of <td>'s containing your row data, finally wrapping the whole row in <tr>.
Perhaps something like this (not fully tested, just to give the idea):
class EditArticles_Form_EditArticles extends Zend_Form
{
protected $model;
public function __construct($model)
{
$this->model = $model;
parent::__construct();
}
public function init()
{
$rows = $this->model->GetArticlesToEdit($this->getUid());
$numRows = count($rows);
for ($i = 0; $i < $numRows; $i++) {
$do = new Zend_Form_Element_Select('myselect' . $i);
$do->addMultiOption('0', 'Aktywny');
$do->addMultiOption('1', 'Nieaktywny');
$do->setDecorators(array(
'ViewHelper',
array(array('cell' => 'HtmlTag'), array(
'tag' => 'td'
)),
array('AnyMarkup', array(
'markup' => $this->_getMarkupForRow($i, $row),
'placement' => 'PREPEND',
)),
array(array('row' => 'HtmlTag'), array(
'tag' => 'tr'
)),
));
$this->addElement($do);
}
}
protected function _getMarkupForRow($i, $row)
{
return '<td>' . $i . '</td>' .
'<td>' . $row['nazwa'] . '</td>' .
'<td>' . $row['typ'] . '</td>' .
'<td>' . $row['rozmiar'] . '</td>';
}
}
A final note: Remember to register an element decorator prefix path as follows (in the form, probably in init()):
$this->addElementPrefixPath('My_Decorator', 'My/Decorator', self::DECORATOR);
This allows the element to resolve the short name AnyMarkup into a full classname My_Decorator_AnyMarkup.

Is there a way to generate views from Zend_Form ? (read-only)

I was wondering if is there an easy way to generate views from form objects when dealing with CRUDs.
I mean, when we have these options: VIEW | EDIT | DELETE
I want my VIEW option like EDIT option, but without form elements, just the values.
This will minimize so much the time spent to create these views.
Someone knowks something like that?
In my last project I had this dilemma too. My solution may not be the most elegant, but it did the job. Mind you, I use a Form viewscript decorator in stead of a full decorator generated elements. But you could adjust this example to use decorators I presume. What I'm showing is a very basic example, to give you a general idea. Here's what I did:
class Cms_Form_Page extends Zend_Form
{
const FOR_CREATE = 'forCreate';
const FOR_READ = 'forRead';
const FOR_UPDATE = 'forUpdate';
const FOR_DELETE = 'forDelete';
protected $_name = 'page';
private $_for;
private $_viewScripts = array(
self::FOR_CREATE => 'page-manager/partials/form-page-create.phtml',
self::FOR_READ => 'page-manager/partials/form-page-read.phtml',
self::FOR_UPDATE => 'page-manager/partials/form-page-update.phtml',
self::FOR_DELETE => 'page-manager/partials/form-page-delete.phtml'
);
public function __construct( $for = self::FOR_CREATE, $options = null )
{
$this->_for = $for;
parent::__construct( $options );
}
public function init()
{
$this->setName( $this->_name )
->setAttribs( array( 'accept-charset' => 'utf-8' ) )
->setDecorators( array(
'PrepareElements',
array( 'ViewScript', array( 'viewScript' => $this->_viewScripts[ $this->_for ] ) ),
'Form'
) );
$elements = array();
swith( $this->_for )
{
case self::FOR_CREATE:
$title = new Zend_Form_Element_Text( 'title' );
$elements[] = $title;
break
case self::FOR_READ:
$id = new Zend_Form_Element_Hidden( 'id' );
$elements[] = $id;
break;
case self::FOR_UPDATE:
$id = new Zend_Form_Element_Hidden( 'id' );
$elements[] = $id;
$title = new Zend_Form_Element_Text( 'title' );
$elements[] = $title;
break;
case self::FOR_DELETE:
$id = new Zend_Form_Element_Hidden( 'id' );
$elements[] = $id;
break;
default:
throw new Exception( 'invalid Form type' );
}
$submit = new Zend_Form_Element_Button( 'submit' );
$elements[] = $submit;
$this->addElements( $elements );
}
}
So, basically, I pass one of the class constants to it's constructor. And based on that value, I determine what elements are needed for the form, and how the elements should be rendered.
For instance, for create you could have a select dropdown form field where you would choose a Locale, where for delete this would be a hidden field (not shown in my example btw).
Hope this has given you some ideas.
PS:
In one of the selected viewscripts you could then simply show the value of an element (along with rendering the hidden element too), with something like:
<?
$form = $this->element;
?>
... some html
// let's presume id and locale are hidden form fields for current form type
// (Cms_Form_Page::FOR_UPDATE for instance)
<?= $form->id->renderViewHelper(); ?>
<?= $form->locale->renderViewHelper(); ?>
// and here we simply output the current locale value
// of course, you should have populated the values in the form somewhere first
<dt>Current locale:</dt>
<dd><?= $form->locale->getValue(); ?></dd>
...etc
So, I think you'ld be best of with using viewscript decorators for the form, or you could roll your own form element decorator that renders the hidden field (if neccesary) and simply shows it's value in some html tag.
Hector from Nabble, show me this, which seems to be the best way:
class Default_View_Helper_FormView extends Zend_View_Helper_Abstract
{
public function formView(Zend_Form $form)
{
$html = "<dl>";
foreach ($form->getElements as $element) {
$html .= "<dt>{$element->getLabel()}</dt>";
$html .= "<dd>{$element->getValue()}</dd>";
}
$html .= "</dl>";
return $html;
}
}
I'm not sure if I understand, but I think that for the view option you can just fetch the data from your model. No need to access them through Zend_Form.
But if you want the make your form read-only, you can add readonly (setAttrib('readonly', 'readonly')) attribute to your elements.
Made a couple minor additions to the accepted answer to cover common elements that may be special cases:
class Default_View_Helper_FormView extends Zend_View_Helper_Abstract
{
public function formView( Zend_Form $form )
{
$html = '<dl>';
foreach ( $form->getElements() as $element ) {
if( $element instanceof Zend_Form_Element_Submit ) {
continue;
}
$html .= '<dt>' . $element->getLabel() . '</dt>';
$value = $element->getValue();
if( $element instanceof Zend_Form_Element_Checkbox ) {
$value = ($value) ? 'Yes' : 'No';
}
else if( $element instanceof Zend_Form_Element_Select ) {
$value = $element->getMultiOption($value);
}
$html .= '<dd>' . $value . '</dd>';
}
$html .= '</dl>';
return $html;
}
}
The only problem with the accepted answer is that you're creating all the elements and then ignoring them.
Using the control logic from fireeyedboy's answer, you could instead switch all the elements to Zend_View_Helper_FormNote which does the same thing.
Just depends on if the optimization matters.

Drupal - Include more than one user_profile_form on a page

Edit:
I think it is because the action is the same or something. I tried to modify the action using this:
function mytheme_user_profile_form($form) {
global $user;
$uid = $user->uid;
//print '<pre>'; print_r($form); print '</pre>';
$category = $form['_category']['#value'];
switch($category) {
case 'account':
$form['#action'] = '/user/'.$uid.'/edit?destination=user/'.$uid;
break;
case 'education':
$form['#action'] = '/user/'.$uid.'/edit/education?destination=user/'.$uid;
break;
case 'experience':
$form['#action'] = '/user/'.$uid.'/edit/experience?destination=user/'.$uid;
break;
case 'publications':
$form['#action'] = '/user/'.$uid.'/edit/publications?destination=user/'.$uid;
break;
case 'conflicts':
$form['#action'] = '/user/'.$uid.'/edit/conflicts?destination=user/'.$uid;
break;
}
//print '<pre>'; print_r($form); print '</pre>';
//print $form['#action'];
$output .= drupal_render($form);
return $output;
}
But, the form action, when the form is actually rendered is unchanged. They're all /user/%uid
Can I modify the form action?
I am including several different "categories" of the user profile form on one page, and the code will correctly output the forms I'm specifying. Each form is in a separate collapsible div.
My problem is twofold.
(1) The existing values for the fields aren't pre-populated and
(2) Clicking on "Save" for one section will result in a warning: Email field is required, regardless of which form you're actually saving
I am pretty sure that for problem #2, it is because the name of the button is the same in all cases, as is the form id.
print '<h3>– Account Settings</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'account'));
print '</div>';
print '<h3>– My Info</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'Personal'));
print '</div>';
print '<h3>– Experience</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'experience'));
print '</div>';
print '<h3>– Education</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'education'));
print '</div>';
Problem #1: ? Could you post the html source?
For problem #2:
OK, I'll step through the code here:
The validation handler for the user profile form (user_profile_form_validate()) calls
user_module_invoke('validate', $form_state['values'], $form_state['values']['_account'], $form_state['values']['_category']);
Which looks like
<?php
/**
* Invokes hook_user() in every module.
*
* We cannot use module_invoke() for this, because the arguments need to
* be passed by reference.
*/
function user_module_invoke($type, &$array, &$user, $category = NULL) {
foreach (module_list() as $module) {
$function = $module .'_user';
if (function_exists($function)) {
$function($type, $array, $user, $category);
}
}
}
?>
So, the validation handler for this form is going through every module looking for user hook functions and calling them with $type = 'validate'. (Note that 'category' param is optional here - contrib modules are not required to use it)
Let's look at user.module's user hook as an example to see what happens:
function user_user($type, &$edit, &$account, $category = NULL) {
if ($type == 'view') {
$account->content['user_picture'] = array(
'#value' => theme('user_picture', $account),
'#weight' => -10,
);
if (!isset($account->content['summary'])) {
$account->content['summary'] = array();
}
$account->content['summary'] += array(
'#type' => 'user_profile_category',
'#attributes' => array('class' => 'user-member'),
'#weight' => 5,
'#title' => t('History'),
);
$account->content['summary']['member_for'] = array(
'#type' => 'user_profile_item',
'#title' => t('Member for'),
'#value' => format_interval(time() - $account->created),
);
}
if ($type == 'form' && $category == 'account') {
$form_state = array();
return user_edit_form($form_state, (isset($account->uid) ? $account->uid : FALSE), $edit);
}
//<-- LOOK HERE -->
if ($type == 'validate' && $category == 'account') {
return _user_edit_validate((isset($account->uid) ? $account->uid : FALSE), $edit);
}
if ($type == 'submit' && $category == 'account') {
return _user_edit_submit((isset($account->uid) ? $account->uid : FALSE), $edit);
}
if ($type == 'categories') {
return array(array('name' => 'account', 'title' => t('Account settings'), 'weight' => 1));
}
}
So, it is only supposed to validate if the category == 'account'
In the function _use_edit_validate, we find:
// Validate the e-mail address:
if ($error = user_validate_mail($edit['mail'])) {
form_set_error('mail', $error);
}
There's your error message.
Since that form is only supposed to validate when the category == 'account', and your problem (#2) seems to be that it always validates regardless of the category, maybe your forms are not being rendered as unique form instances? Drupal might be rendering a complete form each time, and just setting a hidden form value to whatever the category is (like in this form's definition function in user_pages.inc $form['_category'] = array('#type' => 'value', '#value' => $category);)
It would be helpful to see the actual html source output.
==EDIT 10-15-09 in response to updated question===
OK, it looks like your method (editing $form['#action'] manually in the theme layer) may not be possible (see this post for reference). If you want to alter the form action you need to write a custom module that implements hook_form_alter() (it won't work in a theme template file). This function allows you to modify how a form is rendered, in your case the user modification form. There are more details on form modification here.
I am not 100% sure that's what you want to do though; (since it looks like you already must create a module) perhaps you want to hook into hook_user() instead; this function "... allows modules to react when operations are performed on user accounts.". You may be able to react to the category in this function and block/allow whichever user changes you like.
However, if it's just email address validation that is the problem, and if you are dealing with existing users, why don't you just make sure the email address is set before you save?