Showing posts with label Zend. Show all posts
Showing posts with label Zend. Show all posts

Friday, March 26, 2010

Custom message for Zend CSRF token

Ever see the following message when using Zends CSRF token?:

The token 'cea65eff4f464dsl57729a21fbd56aea' does not match the given token 'd2479b415baafe5791ase68f85122828a'

Wouldn't it be more useful to have an intelligible message? To set custom messages for the Zend_Form_Element_Hash do the following:

$this->addElement('hash', 'csrf_token', array(
'salt' => get_class($this) . '',
'timeout' => ,
'errorMessages' => array('Identical' => 'Form has timed out (probably), or you are attempting a cross-site request forgery. Please submit form again.'),
));


'Identical' is the validator that Zend_Form_Element_Hash uses. So adding the errorMessages line when creating the hash should do the trick.

There is probably a setErrorMessages() method also, but I haven't tried this.

Thursday, February 11, 2010

Zend PHPUnit check elements set by controller

When testing output from controllers in Zend using the Zend PHPUnit one might want to check the elements set by the controller, if they have the right values or exist at all.

Anything below top level form ($this->view->form = $form; in controller) one needs to use the getElement() function like one would in the controller. getSubForm() is also valid if there are subforms:

public function testRegisterViewObjectContainsProperties() {
$controller = new RegistrationController(
$this->request,
$this->response,
$this->request->getParams()
);
$controller->registerAction();

$this->assertTrue(isset($controller->view->form));

$this->assertTrue(isset($controller->view));
$this->assertTrue(isset($controller->view->form));
$username = $controller->view->form->getSubForm('userpass')->getElement('username');


http://www.contentwithstyle.co.uk/content/unit-testing-controllers-with-zend-framework seems to be useful.

Zend PHPUnit posting to controller

Sending data to the controller to check what you get back can be tricky. Especially if you have subforms or file uploads.

Here is how if you have subforms (in this case a select and a multiselect in separate subforms):
public function testPostMissingFilledFields() {
$this ->request ->setMethod('POST')
->setPost(array(
//Selected element with value '2'
'firstLayerSubform1' =>
array('secondLayerSubform1' =>
array('thirdLayerSubform1' =>
array('select' => array('2')))),
//Selected elements with values 1159 and 1161
'firstLayerSubform2' =>
array('secondLayerSubform2' =>
array('thirdLayerSubform2' =>
array('multiselect' => array('1159', '1161')))),
));


Useful functions to see what you submit look like are:
In Test file:
var_dump($this->request->getParams());
In controller:
var_dump($this->_request->getParams());

If you find a way to check for uploaded files please tell me. :)

PHPUnit with Zend View

When you want to check if important objects in Zend Views show up using PHPUnit testing can be used. In my case I have a registration form which repopulated the fields if one was missing or if anything was incorrectly filled in.

There seem to be multiple ways to select elements in the DOM:
- assertQuery - CSS selector
- assertXpath - Xpath selector
- strpos (!) - search through the html as a string

I first tried CSS selector:
$this->assertQuery('input[id="username"][value="test1"]'); //username
$this->assertQuery('input#username[value="test1"]'); //username
$this->assertQuery("input[value='test@asdf.com']"); //emailaddress


All should work, but there are different problems. The two first selections don't work, event though they work in firebug. The last line doesnt work either because of the period '.' which gives a "DOMXPath::query(): Invalid predicate" error.
Seems Zend PHPUnit converts from CSS to Xpath selectors and doesnt manage to do it right.

Therefore using Xpath directly is better. (Download the FireXpath extension to Firebug for Firefox and play around to learn it (also http://www.w3schools.com/XPath/default.asp is good)). So here's Xpath:
$this->assertXpath("//input[@id='username'][@value='test1']"); //username
$this->assertXpath("//input[@id='emailaddress'][@value='test@asdf.com']"); //emailaddress

Works out of the box.

Alternatively you can search through the html code linearly:
$this->assertTrue(strpos($this->_response->getBody(), 'test@asdf.com') !== false); //emailaddress
However, if anything changes in the html code, the test might fail.

Solution sources: http://framework.zend.com/manual/en/zend.test.phpunit.html, http://www.tig12.net/downloads/apidocs/zf/, others I cant remember.

Friday, February 5, 2010

Atomic transactions in Zend

If you have many database changes where all need to succeed or none at all do the following:

//Get a hold of the database adapter:
$model = new Model_DbTable_();
$adapter = $model->getAdapter();
$adapter->beginTransaction();
try {
//Do inserts, updates, deletes etc.
//Commit the changes and do rollback if it fails:
$adapter->commit();
}
catch (Exception $e) {
$user->getAdapter()->rollback();
//Print errors
$echo $e->getMessage();
}


or similarly:

$db->beginTransaction();
try {
$db->insert('server', array('key' => 'foo', 'value' => 'bar'));
$db->insert('server', array('key' => 'bar', 'value' => 'baz'));
$db->insert('server', array('key' => 'baz', 'value' => 'foo'));

$db->commit();
}
catch (Exception $e) {
$db->rollback();
$e->getMessage();
}


Solution found: http://devzone.zend.com/article/1367

'not found in haystack' error in Zend

If you get a '%value%' was not found in the haystack' error when using select boxes in Zend, add the following to the form element:

$element->setRegisterInArrayValidator(false);

or directly when creating form:

$form->addElement('multiselect', 'elementname', array('RegisterInArrayValidator' => false));

Solution found at: http://stackoverflow.com/questions/991001/zendvalidatebetween-strange-error-message