New jQuery 1.3 and its user interface have a lot of great features. But if we want to use our jQuery validation plugin with 1.3 version we need to upgrade plugin version to 1.5.1 (or higher), which is still compatible with 1.2.6. New Validate Plugin version (1.5.2) came up with some nice features like integration with UI Tabs. The following example shows a real implementation of user profile form divided in three sections.
In my example i will use sfGuardPlugin + one table for user profile.
First, we need to generate new project, new application and setup database configuration:
<?php
symfomy generate:project sfTest
symfomy generate:app frontend
symfomy configure:database "mysql:host=localhost;dbname=sf_test" user pass
?>
Next step is to install sfGuardPlugin:
symfony plugin:install sfGuardPlugin
and enable it according to its documentation.
Now we can put profile table structure into schema.yml file:
propel:
sf_guard_profile:
id: ~
user_id: { type: integer, foreignTable: sf_guard_user, foreignReference: id, required: true, onDelete: cascade }
email: { type: varchar(128), index:unique, required: true }
name: { type: varchar(128), required: true }
surname: { type: varchar(128), required: true }
education: longvarchar
company: varchar(128)
position: varchar(128)
phone_number: { type: varchar(30), required: true }
fax: varchar(25)
comunicator: varchar(30)
country: { type: varchar(128), required: true }
city: { type: varchar(128), required: true }
province: { type: varchar(128), required: true }
address: { type: varchar(255), required: true }
zipcode: varchar(15)
Remember to set profile configuration into app.yml:
all:
sf_guard_plugin:
profile_class: SfGuardProfile
profile_field_name: user_id
Then:
symfony propel:build-all
and create module for our example:
symfony generate:module frontend user
Now we need to download all neccessary JavaScript files:
- jquery-1.3.2.js
- jquery-ui-1.7.1.js
- jquery.validate-1.5.2.js
As i did in the previous post , after downloading new jquery validation plugin we need to make some changes in jquery.validation.js file, so it could work properly with Symfony sfForm (conversion form “name” to “id”). You can find corrected file here.
We can put our bussiness logic to executeProfile action into actions.class.php but earlier we have to create our ProfileForm.class.php - we can put that file into global lib/form/ directory or lib/form of current module.
ProfileForm.class.php:
<?php
class ProfileForm extends sfGuardUserAdminForm {
public function configure() {
parent::configure();
$this->unsetAllExcept(array(
'username',
'email',
'name',
'surname',
'education',
'company',
'position',
'phone_number',
'phone_number_2',
'fax',
'communicator',
'country',
'city',
'province',
'zipcode',
'address',
'address_2'
));
# Edit default validators schema
$this->validatorSchema['email'] = new sfValidatorEmail();
$this->widgetSchema->setNameFormat('profile[%s]');
}
protected function doSave($con = null){
if (is_null($con)) {
$con = $this->getConnection();
}
$this->updateObject();
$this->object->save($con);
}
}
?>
The unsetAllExcept method was presented in this post.
actions.class.php:
<?php
class userActions extends sfActions {
public function executeIndex(sfWebRequest $request) {
$this->forward('user', 'profile');
}
public function executeProfile($request) {
$user = $this->getUser()->getGuardUser();
$this->form = new ProfileForm($user);
if ($request->isMethod('post') && $request->hasParameter('profile')) {
$this->form->bind($request->getParameter('profile'));
if ($this->form->isValid()) {
$this->form->save();
$this->getUser()->setFlash('msg', 'Your profile has been successfully updated');
} else {
$this->getUser()->setFlash('msg', 'Sorry, there are some errors listed below. ');
}
}
}
}
?>
Nothing special so far, but now we need to take care of our view file.
In profile template we have to split form into for example three sections: identity, experience and location. Then we can add jquery tabs and validation:
profileSuccess.php:
<h1> Update user profile</h1>
<?php if ($sf_user->hasFlash('msg')): ?>
<div class="message"><?php echo $sf_user->getFlash('msg') ?></div>
<?php endif; ?>
<form action="<?php echo url_for('user/profile') ?>" id="profileForm" method="post" >
<div id="tabs">
<ul>
<li><a href="#identity"><span>Identity data</span></a></li>
<li><a href="#experience"><span>Experience/Job information</span></a></li>
<li><a href="#location"><span>Location</span></a></li>
</ul>
<div id="identity">
<table>
<?php echo $form['username']->renderRow() ?>
<?php echo $form['email']->renderRow() ?>
<?php echo $form['name']->renderRow() ?>
<?php echo $form['surname']->renderRow() ?>
</table>
</div>
<div id="experience">
<table>
<?php echo $form['education']->renderRow() ?>
<?php echo $form['company']->renderRow() ?>
<?php echo $form['position']->renderRow() ?>
<?php echo $form['phone_number']->renderRow() ?>
<?php echo $form['fax']->renderRow() ?>
</table>
</div>
<div id="location">
<table>
<?php echo $form['country']->renderRow() ?>
<?php echo $form['province']->renderRow() ?>
<?php echo $form['city']->renderRow() ?>
<?php echo $form['address']->renderRow() ?>
<?php echo $form['zipcode']->renderRow() ?>
</table>
</div>
</div>
<input type="submit" value="Update profile" />
</form>
<?php javascript_tag(); ?>
$(document).ready(function(){
var tabs = $("#tabs").tabs();
var validator = $("#profileForm").validate({
rules: {
profile_username: "required",
profile_email: {
required: true,
email: true
},
profile_name: "required",
profile_surname: "required",
profile_phone_number: {
required: true,
number: true
},
profile_country: "required",
profile_province: "required",
profile_city: "required",
profile_address: "required"
},
errorPlacement: function(label, element) {
label.insertAfter(element);
}
});
validator.focusInvalid = function() {
if( this.settings.focusInvalid ) {
try {
var focused = $(this.findLastActive() || this.errorList.length &amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp; this.errorList[0].element || []).filter(":hidden");
tabs.tabs("select", tabs.find(">div").index(focused.parents('div:first')));
focused.focus();
} catch(e) {
// ignore IE throwing errors when focusing hidden elements
}
}
};
});
<?php end_javascript_tag(); ?>
Putting it together with server side validation provided by Symfony forms, we have nice, simple and complex forms validation system that should look like this:


Awesome! Would it be possible to extract the validation rules from the symfony form class straight to the JS?
Yes, it is possible. There are many ways. You can do that for example as Ahmed proposed in last comment: http://blog.adryjanek.eu/2009/01/15/symfony-12-using-sfform-with-jquery-validate-plugin/#comment-522