How can I use the sfValidatorEmail validator in Symfony to validate a single email field - email

I have a form with 2 elements that will be submitted and then update part of a user profile.
I don't want to use the entire generated form and have to remove all the fields except for the two I need. I just want to be able to create a quite simple form to do my update.
Is there a way to utilize Symfony's sfValidatorEmail inside the action on the returned value of an email field?
Since the regex is already written in the validator, I would like to reuse it, but I don't know how to use it in the action after the non-symfony form has been submitted.

Two approaches here - you could construct a simple form anyway extending from sfForm/sfFormSymfony (doesn't have to be ORM-based) that just contains the 2 fields you want. That way you can use the existing validation framework, and then use $myForm->getValues() after everything has been validated to get your values for your profile update.
Alternatively, as you've mentioned, you can use the sfValidatorEmail class in your action like so:
$dirtyValue = "broken.email.address"
$v = new sfValidatorEmail();
try
{
$v->clean($dirtyValue);
}
catch (sfValidatorError $e)
{
// Validation failed
}
The latter approach quickly leads to messy code if you have many values that need cleaning, and it's worth putting the logic back into a form to handle this in the usual manner.

If you're submitting a form with 2 elements, it should be a form on the edit and update end, period. Symfony forms are lightweight, there's no performance reason to not use them. Instead, make a custom form for this purpose:
class ProfileUpdateForm extends ProfileForm
{
public function configure()
{
$this->useFields(array('email', 'other_field'));
}
}

Related

Symfony 2.x Form Field Name

When I render a form, form Filed Name is given as an array. For example: search[item], search[keyword] etc. where search is name of the form.
I'm not great on working with forms but I think, the name should be rendered as simply, name="item" or name="keyword".
I've looked at all the documentation, customizing form rendering topic etc. but I can't find any way to change the default behaviour of Symfony form to render form filed name from 'search[item]' to 'item'.
This way, when I ask for the POST data, I can ask simply $this->getRequest()->request->get('item'), as I have to deal with lots of individual parameters.
Help would be great i) To figure out how to achieve what I want. ii) to let me know, why the name is rendered this way. is this the good practice?
Rather than accessing parameters from the Request object, you can bind the Request object to the form.
For example, in your controller method that you post your form to:
namespace Acme\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Acme\Form\MyFormClass;
class MyFormController extends Controller
{
receiveFormAction(Request $request)
{
$form = new MyFormClass();
// you can specify that a route only accepts a post
// request in the routing definition
if ($request->isMethod('POST')) {
// this populates the form object with the data
// from the form submission
$form->bind($request);
if ( ! $form->isValid()) {
throw new \Exception('Invalid form');
}
// an array of the data the format you require
$data = $form->getData();
$data['item'];
$data['keyword'];
// etc.
}
}
}
The above is the way you should be handling forms in Symfony 2, and is how you can leverage the power that the forms component gives you, with validation etc.
Symfony supports multiple forms on a page. They might be instances of the same form or have similar field names. Having the fields for each form all together in an array makes this easy to do.

Zend creating forms based on requests within one controller/action

I don't really know how to word the title well, but here's my issue. I decided instead of having 25 controllers to handle pages, I have one PageController with a viewAction that takes in a :page parameter - for example, http://localhost/website/page/about-us would direct to PageController::viewAction() with a parameter of page = about-us. All of the pages are stored in a templates folder, so the viewrenderer is set to render application\templates\default\about-us.phtml.
I did this so I can consolidate and it seemed like a better approach. My question is the following: lets say when the page request is contact-us, I would need a Zend_Form to be used within the contact page. So, I would need a way within PageController::viewAction() to recognize that the page needs to have a form built, build the form, and also upon submission the need to process it (maybe this should be handled in an abstract process method - not sure).
I have no idea how to implement this. I thought maybe I can store a column with the name of a form and a connecting page identifier. Even better, create a one-to-many page to forms, and then in the submission loop through the forms and check if submitted and if so then process it (maybe there is a isSubmitted() method within zend_form. I really don't know how to handle this, and am looking for any help i can get.
Thanks!
Here is something that came to mind that may work or help point you in a direction that works for you.
This may only work well assuming you were to have no more than one form per page, if you need more than one form on a page, you would have to do something beyond this automatic form handling.
Create a standard location for forms that are attached to pages (e.g. application/forms/page). This is where the automatic forms associated with pages will be kept.
In your viewAction, you could take advantage of the autoloader to see if a form for that page exists. For example:
$page = $this->getParam('page');
$page = ucfirst(preg_replace('/-(\w)/ie', "strtoupper('$1')", $page)); // contact-us -> ContactUs
$class = 'Application_Form_Page_' . $page;
// class_exists will invoke the autoloader to map a class to a file
if (class_exists($class)) {
// a form is defined for this page
$form = new $class();
// check if form was posted
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost()) {
// form is valid - determine how to process it
}
}
// assign the form to the view
$this->view->pageForm = $form;
}
All this really leaves out is the action you take to process a specific form. Since the contact form will likely generate an email, and another form may insert data into a database, you will need some sort of callback system or perhaps another class that can be mapped automatically which contains the form processor code.
Anyway something along those lines is what came to mind first, I hope that helps give you some more ideas.

Zend Validate: How to validate each separate value in comma separated values in textarea for zend_validate_DbRecordExist?

I have text box in which your adds values in comma separated values. Once the form is post I want to check each of CSV value against database table that if each one of them exist already. If so then I want to throw error message otherwise that is fine.
How can I implement this?
What you need is a custom validator. you can either do it extending Zend_Validate_Abstract or you can simply use a callback validator.
To do so, you need to add this to your element:
$elem = new Zend_Form_Element_Text('elem_name');
$elem->setLabel('Label Name:')
->setRequired(true)
->addValidator('callback', true, array('callback' => array($this, 'functionName')));
$this->addElement($elem);
And in the same class (usually your form is in a class that extends Zend_Form), you add this method:
public function functionName($csvString) {
// stuff here using explode(',', $csvString)
// foreach() to iterate over the result and match against the db each $value
}
See explode() for more information.
However, if your form element is going to be called more than once, and in different forms, then I don't recommend you to use a callback, but you'd better write your own validator, the theory remains the same though. Take a look here for more information about how to write validators.
I really doubt that this can be achieved directly just using Zend_Validate_Db_RecordExists. I think the best solution would be to create a custom validator for this purpose. Something that would take your value then explode it based on a , $valueArray = explode(',', $value); and then for each $valueArray check if the element exists in the db. This shouldn't be too hard. If you dont have idea about custom validators this might be helpful.

How to remove a validator from a Select?

I have a form where I need to add/remove validators dynamically. Based on a dropdown selection, other form fields may have different validation rules.
For other kinds of inputs, I've used replace(methodThatCreatesTheInput()) to get rid of a previously added validator. (Not knowing of a better way. Specifically, there doesn't seem to be any way to directly remove a validator from a component...)
With Select, from wicket-extensions, this approach fails with something like:
WicketMessage: submitted http post value [[Ljava.lang.String;#5b4bf56d]
for SelectOption component [8:myForm:targetInput] contains an
illegal relative path element [targetConsortiums:1:option] which does not
point to an SelectOption component. Due to this the Select component cannot
resolve the selected SelectOption component pointed to by the illegal value.
A possible reason is that component hierarchy changed between rendering and
form submission.
The method that creates the Select:
private FormComponent<?> targetSelection() {
Map<Class<? extends Target>, List<Target>> targets = targetService.getAllAsMap();
SelectOptions<Target> propertyOptions = new SelectOptions<Target>("targetConsortiums",
targets.get(Consortium.class), new TargetRenderer());
SelectOptions<Target> consortiumOptions = new SelectOptions<Target>("targetProperties",
targets.get(Property.class), new TargetRenderer());
Select select = new Select(ID_TARGET, new PropertyModel<Target>(model, "target"));
select.add(propertyOptions);
select.add(consortiumOptions);
select.setRequired(true);
select.setMarkupId(ID_TARGET);
return select;
}
(Why use a Select instead of normal DropDownChoice? We want the two types of choices to be clearly separated, as documented in this question.)
Any ideas how to solve this? What I'm trying to achieve is, of course, very simple. Unfortunately Wicket disagrees, or I'm using it wrong.
Wicket 1.4.
I don't know how to do this on Wicket 1.4, but on Wicket 1.5 there is a remove method for validators on FormComponent (see javadoc)

Loading models in Zend_Form using Zend Framework

I'm trying to build a form using the Zend_Form component, but the number of elements varies. The information for each Zend_Form element is stored in a database (name, options, validators, filters, etc.).
The application I'm working on consists of building surveys which contain a varying number of questions. Each question is associated with different arrays of answers. Ultimately my goal is to build arrays of radio/checkbox buttons, dynamically, server-side.
I'm looking for a pretty way to generate my form, but I'm not sure of the best way to load the model within the form. Should the model be loaded in the controller then passed (somehow, via a parameter?) directly to the form, or is it better to load the model within the Form init() method? Where's the best place to put the logic, should it be within the form class, or within the controller, or within the model?
My idea is to fetch form element properties (name, rules, filters, etc.) in the database, then iterate and finally render the form. What do you think of this approach? Ultimately, elements will be dynamically added (client-side), this time, using AJAX and a JavaScript library (such as jQuery).
Here are a couple useful links I found via Google, but I think they all answer a slightly different question than mine:
On building dynamic forms, server side:
http://framework.zend.com/wiki/display/ZFPROP/Zend_Form+generation+from+models+-+Jani+Hartikainen
http://weierophinney.net/matthew/archives/200-Using-Zend_Form-in-Your-Models.html
http://codeutopia.net/blog/2009/01/07/another-idea-for-using-models-with-forms/
On building dynamic forms, client side, with AJAX processing:
http://www.jeremykendall.net/2009/01/19/dynamically-adding-elements-to-zend-form/
I think I found a possible solution, it involves passing an array of Zend Form elements to the Zend Form::__construct() method. The constructor takes an array of options, one of them is called "elements". Have a look at the source code within the Zend Framework library.
I coded a new private method within the controller, called buildSurveyForm(). Note : the object, passed as a parameter, is built from a huge SQL query with half a dozen JOIN statements, fetching data from a few tables (surveys, questions, answers, etc.) within the database. One of the public attributes for this class consists of an array of questions, stored as objects (with public methods/attributes as well, etc.). Same for answers. The code for building these classes is pretty trivial and out of topic here.
Here's the code within the survey controller. I copy/pasted and edited/dropped a few lines to make it a lot clearer :
private function buildSurveyForm(MyApp_Object_Survey $survey)
{
foreach ($survey->questions as $question)
{
$element = new Zend_Form_Element_MultiCheckbox($question->order);
$element->addMultiOptions($question->getAnswersLabels());
$element->setName($question->order);
$element->setLabel($question->title);
$elements[] = $element;
}
// Here's the trick :
$formOptions = array('elements' => $elements);
$surveyForm = new MyApp_Survey_Form($formOptions);
$urlHelper = $this->_helper->getHelper('url');
$surveyForm->setAction($urlHelper->url(array(
'controller' => 'survey',
'action' => 'vote'),
'default'
));
$surveyForm->setMethod('post');
$this->_forms['survey'] = $surveyForm;
return $this->_forms['survey'];
}
The MyApp Survey Form class only contains a Submit button within the init() method. The dynamically generated elements with the code above are added BEFORE this submit button (which is unexpected, but useful). This class simply extends Zend_Form.
Then, within survey controller / view action :
public function viewAction()
{
$surveyModel = $this->_model['survey'];
$survey = $surveyModel->getFullSurvey($this->_getParam('id'));
$survey = new MyApp_Object_Survey($survey);
// Calls above private method :
$surveyForm = $this->buildSurveyForm($survey);
$this->view->assign(array(
'surveyForm' => $surveyForm,
));
}
Adding filters, validators and decorators to form elements is now trivial. My proposal is a bit dirty, but I think it gets the job done. I will add a new proposal if I find something more elegant. Feel free to post different answers/solutions.
You could extend Zend_Form.
Zend form is not good place for logic, only form representation.
So, Load all needed elements using model in controller and pass them to the form in contructor as parameters.