Arbitrary Form Processing with Drupal - forms

I am writing a module for my organization to cache XML feeds to static files to an arbitrary place on our webserver. I am new at Drupal development, and would like to know if I am approaching this the right way.
Basically I:
Expose a url via the menu hook, where a user can enter in a an output directory on the webserver and press the "dump" button and then have PHP go to drupal and get the feed xml. I don't need help with that functionality, because I actually have a prototype working in Python (outside of Drupal)..
Provide a callback for the form where I can do my logic, using the form parameters.
Here's the menu hook:
function ncbi_cache_files_menu() {
$items = array();
$items['admin/content/ncbi_cache_files'] = array(
'title' => 'NCBI Cache File Module',
'description' => 'Cache Guide static content to files',
'page callback' => 'drupal_get_form',
'page arguments' => array( 'ncbi_cache_files_show_submit'),
'access arguments' => array( 'administer site configuration' ),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
I generate the form in:
function ncbi_cache_files_show_submit() {
$DEFAULT_OUT = 'http://myorg/foo';
$form[ 'ncbi_cache_files' ] = array(
'#type' => 'textfield',
'#title' => t('Output Directory'),
'#description' => t('Where you want the static files to be dumped.
This should be a directory that www has write access to, and
should be accessible from the foo server'),
'#default_value' => t( $DEFAULT_OUT ),
'#size' => strlen( $DEFAULT_OUT ) + 5,
);
$form['dump'] = array(
'#type' => 'submit',
'#value' => 'Dump',
'#submit' => array( 'ncbi_cache_files_dump'),
);
return system_settings_form( $form );
}
Then the functionality is in the callback:
function ncbi_cache_files_dump( $p, $q) {
//dpm( get_defined_vars() );
$outdir = $p['ncbi_cache_files']['#post']['ncbi_cache_files'];
drupal_set_message('outdir: ' . $outdir );
}
The question: Is this a decent way of processing an arbitrary form in Drupal? I not really need to listen for any drupal hooks, because I am basically just doing some URL and file processing.
What are those arguments that I'm getting in the callback ($q)? That's the form array I guess, with the post values? Is this the best way to get the form parameters to work on?
Thanks for any advice.

You can process forms in two stages, validate and submit.
Validate is for when you want to validate some user provided and raise form errors if some user input was invalid (like an invalid url or email address)
Submit which is the one you use is called if a form passes all of its validations, so at that point if you made a proper validation you will know that the data supplied by the user is okay.
Your submit function should look like this:
function ncbi_cache_files_dump(&$form, &$form_state) {
// $form: an array containing the form data
// $form_state: data about the form, like the data inputted in the form etc.
// code...
}

I think you need 2 separate forms here:
for setting the directory (the one you have now);
for making a dump (another form that would use the configured path).
Also it seems logical to publish the previously saved path as the default value in the settings form (instead of a hard-coded path).
And in general you should check the form input data from the second parameter of the submit callback:
function ncbi_cache_files_dump(&$form, &$form_state) {
$outdir = $form_state['values']['ncbi_cache_files'];
// ...
}

Related

Drupal 7: Show fields on a form based on another field and a database lookup

I have a form I created in a custom module using the Form API. It is a fairly basic form with only 4 fields. It basically signs a user up for a job alert system. We are basing it only by email address with a few search parameters. We want people to be able to setup a search agent quickly and anonymously meaning they will NOT be creating a Drupal user account as we don't want them to have to deal with a password etc. They will just put in their email address, check off a few preferences and we will save the data.
Now the issue I need to deal with is allowing the user to edit their preferences later on and/or unsubscribe. Again this is not high security and it doesn't need to be. What I would like to do is initially ask ONLY for their email address in the form and allow them to submit it. I would then check the database to see if we already have an entry for that email address and if so, display the pre-filled form for them to edit or unsubsribe, other wise just show them the blank form. So I am just trying to figure out the best way to go about this. I'm thinking I just have one form with all of the fields including email address, but somehow only display the other fields besides the email address after a successful call to the database. I'm just tripping up on how to accomplish this.
EDIT:
I'm wondering if I can use Drupal's AJAX functionality to accomplish this? I tried this, but I couldn't get it to work. I put an Ajax attribute on my submit button with a wrapper ID and a callback function. I created a form element in my form with blank markup and used a prefix and suffix that created a wrapper div with the ID I used in my AJAX parameter. Then I am thinking in my callback function I can do the database lookup and then return the form elements I need either pre-filled or not into the wrapper div that was created, but when I do this, the form does submit via AJAX and I get the spinning wheel, but no matter what I return in my callback, it does not appear in my output wrapper div. Am I going about this the right way? I also made sure I have $form_state['rebuild'] = TRUE; on my original form.
Here is what I tried and it didn't work.
/**
* Implements hook_form().
*/
function _vista_form($form, &$form_state) {
$form = array();
$form_state['rebuild'] = TRUE;
$form['email'] = array(
'#type' => 'textfield',
'#title' => 'Email',
'#required' => TRUE,
);
$form['render_area'] = array(
'#type' => 'markup',
'#markup' => '',
'#prefix' => '<div id="job-agent-form">',
'#suffix' => '</div>',
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
'#attributes' => array('class' => array('submit')),
'#ajax' => array(
'callback' => '_display_form',
'wrapper' => 'job-agent-form',
'method' => 'replace',
'effect' => 'fade',
),
return $form;
}
function _display_form($form, &$form_state) {
// there are other form elements that would go here also, I just added two for example
$type_options = array(
'VISTA-HealthCare-Partners-Government' => 'Vista Healthcare Partners',
'International' => 'International Locum Tenens',
'Permanent' => 'Permanent Physician',
'US-Locum-Tenens' => 'US Locum Tenens',
);
$form['job_type'] = array(
'#type' => 'checkboxes',
'#multiple' => TRUE,
'#title' => 'Type of Job',
'#options' => $type_options,
'#empty_option' => 'Choose a placement type',
'#empty_value' => 'all',
//'#default_value' => $type_selected,
);
$form['active'] = array(
'#type' => 'checkbox',
'#title' => 'Subscribe/Unsubscribe',
'#default_value' => 1,
);
return $form;
}
I would go for creating all fields in the form than use hook_form_alter() to hide the unneeded ones with ['#access'] = FALSE.

SugarCRM- How to get POPUP when click on Save button?

I want when click Save in Edit View of some module (example Contact) to get pop up with some message (later I will get options OK and Cancel on that pop up.).
My function
YAHOO.SUGAR.MessageBox.show({msg: 'Foo'} );
is working when I put it at top of editviewdefs.php (I also must include
cache/include/javascript/sugar_grp_yui_widgets.js) ) file and when opening that view I am getting that pop up. But I want it to popup on Save,not when opening EditView (this was just testing that showed me that YAHOO function is working). So I try to create seperate customJavascript.js file in custom/modules/Contacts:
//<script type="text/javascript"
src="cache/include/javascript/sugar_grp_yui_widgets.js"></script>
function check_custom_data()
{
YAHOO.SUGAR.MessageBox.show({msg: 'Foo'} );
}
I modified custom/modules/Contacts/metadata/editviewdefs.php
<?php
$module_name = 'Contacts';
$viewdefs ['Contacts'] =
array (
'EditView' =>
array (
'templateMeta' =>
array (
'form' =>
array (
'hidden' =>
array (
0 => '<input type="hidden" name="opportunity_id" value="{$smarty.request.opportunity_id}">',
1 => '<input type="hidden" name="case_id" value="{$smarty.request.case_id}">',
2 => '<input type="hidden" name="bug_id" value="{$smarty.request.bug_id}">',
3 => '<input type="hidden" name="email_id" value="{$smarty.request.email_id}">',
4 => '<input type="hidden" name="inbound_email_id" value="{$smarty.request.inbound_email_id}">',
),
),
array(
'buttons' =>
array (
0 =>
array(
'customCode' =>
'<input title="Save [Alt+S]" accessKey="S" onclick="this.form.action.value=\'Save\'; return check_custom_data();" type="submit" name="button" value="'.$GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL'].'">',
),
1 =>'Cancel'
)
),
'includes'=> array(
array('file'=>'custom/modules/Contacts/customJavascript.js'),
),
..........
.......
but when I click Save in EditView nothing happens but I want in that moment to get pop up with message (later I will add OK and Cancel options).
What am I doing wrong?
thank you
Updated with code for pop up only with some condition:
....
window.formToCheck = formname;
var contactTypeField = document.getElementById('first_name');
if (contactTypeField.value == 'Tori')
{
if (confirm("This dialog will pop-up whenever the user click on the Save button. "
+ "If you click OK, then you can execute some custom code, and then "
+ "execute the old form check function, which will process and submit "
+ "the form, using SugarCRM's standard behavior.")) {
var customCodeVariable = 5;
customCodeVariable = 55 + (customCodeVariable * 5);
return window.old_check_form(formname);
}
return false;
}
There are a number of ways to do things in SugarCRM, which makes it both very powerful and at times very difficult to customize - as there are so many different options available to you.
To make some kind of pop-up, or any custom log, happen upon clicking the "Save" button, I'd recommend the below solution rather than altering the editviewdefs.
The below solution does not require you modify any core SugarCRM files, so it is upgrade safe and can easily be installed on another instance.
What you will need to do is create a custom installable package, and install it into SugarCRM using the Module Loader.
This is the layout of the directory structure you will ultimately need to end up with:
SugarModuelPopUp
->custom
->include
->customPopUps
->custom_popup_js_include.php
->customPopUpContacts.js
->manifest.php
Create the SugarModuelPopUp folder, which will server as the root of this custom package.
Inside of SugarModuelPopUp, create a new PHP file with the name manifest.php. This file tells SugarCRM how to install the package.
In manifest.php, paste the following code:
<?php
$manifest = array(
array(
'acceptable_sugar_versions' => array()
),
array(
'acceptable_sugar_flavors' => array()
),
'readme' => 'Please consult the operating manual for detailed installation instructions.',
'key' => 'customSugarMod1',
'author' => 'Kyle Lowry',
'description' => 'Adds pop-up dialog on save on Contacts module.',
'icon' => '',
'is_uninstallable' => true,
'name' => 'Pop-Up Dialog On Save',
'published_date' => '2013-03-06 12:00:00',
'type' => 'module',
'version' => 'v1',
'remove_tables' => 'prompt'
);
$installdefs = array(
'id' => 'customSugarMod1',
'copy' => array(
array(
'from' => '<basepath>/custom/',
'to' => 'custom/'
)
),
'logic_hooks' => array(
array(
'module' => 'Contacts',
'hook' => 'after_ui_frame',
'order' => 1,
'description' => 'Creates pop-up dialog on save action.',
'file' => 'custom/include/customPopUps/custom_popup_js_include.php',
'class' => 'CustomPopJs',
'function' => 'getContactJs'
)
)
);
Next, you will want to make the custom folder. Inside of that, create the include folder. Inside of that, create the customPopUps folder.
Next, you will want to create the custom_popup_js_include.php file. This file controls when and where your custom JavaScript gets included on the page. Paste in the below code:
<?php
// prevent people from accessing this file directly
if (! defined('sugarEntry') || ! sugarEntry) {
die('Not a valid entry point.');
}
class CustomPopJs {
function getContactJs($event, $arguments) {
// Prevent this script from being injected anywhere but the EditView.
if ($_REQUEST['action'] != 'EditView') {
// we are not in the EditView, so simply return without injecting
// the Javascript
return;
}
echo '<script type="text/javascript" src="custom/include/customPopUps/customPopUpContacts.js"></script>';
}
}
Next you will need to create the customPopUpContacts.js file, which will create the custom pop-up upon clicking the Save button in the Contacts module EditView. Paste in the below code:
function override_check_form() {
// store a reference to the old form checking function
window.old_check_form = window.check_form;
// set the form checking function equal to something custom
window.check_form = function(formname) {
window.formToCheck = formname;
// you can create the dialog however you wish, but for simplicity I am
// just using standard javascript functions
if (confirm("This dialog will pop-up whenever the user click on the Save button. "
+ "If you click OK, then you can execute some custom code, and then "
+ "execute the old form check function, which will process and submit "
+ "the form, using SugarCRM's standard behavior.")) {
// you have clicked OK, so do some custom code here,
// replace this code with whatever you really want to do.
var customCodeVariable = 5;
customCodeVariable = 55 + (customCodeVariable * 5);
// now that your custom code has executed, you can let
// SugarCRM take control, process the form, and submit
return window.old_check_form(formname);
}
// the user clicked on Cancel, so you can either just return false
// and leave the person on the form, or you can execute some custom
// code or do whatever else you want.
return false;
}
}
// call the override function, which will replace the old form checker
// with something custom
override_check_form();
Once you have created the above directory structure, and the files in the correct folders, you can create a ZIP file of the project. It is important to note that for SugarCRM installable packages, your ZIP file must contain everything in the project directory. That is, you will not be zipping up the SugarModuelPopUp folder, but rather everything inside of it.
Next, you will want to install the custom package using SugarCRM's module loader. You can do this by:
Go to the SugarCRM Admin page.
Click on "Module Loader".
Click on "Browse" and select the ZIP package.
Click on the "Upload" button.
Once the package is uploaded, find its entry in the list of installable packages, and click on "Install"; proceeding with the standard SugarCRM installation process.
With this custom package installed, whenever you click on the "Save" button in the Contacts module EditView, a dialog will pop-up. You can replace the dialog code with anything you want, so as log as you don't modify the code framing it.
Further, you should be able to use this project as a foundation for future function additions to SugarCRM EditViews. Any module which uses the check_form method upon clicking of the "Save" button can have this kind of custom logic executed.
To do so for Accounts, for example, you would do the following:
Add an entry to the logic_hooks array element in manifest.php for Accounts.
'logic_hooks' => array(
array(
'module' => 'Contacts',
'hook' => 'after_ui_frame',
'order' => 1,
'description' => 'Creates pop-up dialog on save action.',
'file' => 'custom/include/customPopUps/custom_popup_js_include.php',
'class' => 'CustomPopJs',
'function' => 'getContactJs'
),
array(
'module' => 'Accounts',
'hook' => 'after_ui_frame',
'order' => 1,
'description' => 'Creates pop-up dialog on save action.',
'file' => 'custom/include/customPopUps/custom_popup_js_include.php',
'class' => 'CustomPopJs',
'function' => 'getAccountJs'
)
)
Add a new method to the CustomPopJs in the custom_popup_js_include.php file for the Accounts JavaScript.
function getAccountJs($event, $arguments) {
// Prevent this script from being injected anywhere but the EditView.
if ($_REQUEST['action'] != 'EditView') {
// we are not in the EditView, so simply return without injecting
// the Javascript
return;
}
echo '<script type="text/javascript" src="custom/include/customPopUps/customPopUpAccounts.js"></script>';
}
Create the customPopUpAccounts.js file, and use the customPopUpContacts.js code as a base for the functionality you want.
There are other ways of accomplishing your goal in SugarCRM, but this is the one I use personally, and it has the benefit of being upgrade safe and easily migratable to other SugarCRM instances.
I have SugarCRM CE 6.5 and this method didn't work to me (I mean creating the new module). However, I modified the logic_hook and put the files directly in custom/include folder and it works!

Form with managed files weird behaviour on form error

I have created a content type with an associated image field.
Each user is able to see a list of all the nodes of this content type and should be able to upload a new image in the appropriate field.
I've tried many solutions, but in the end I'm trying with a form and managed files.
In the page with the list of all the nodes I'm creating a lightbox with a form for each node.
Each form is created like this:
function coverupload_form($form, &$form_state, $uid, $relid) {
$form['#attributes']['id'] = 'coverup-'.$relid;
$form_state['storage']['rid'] = $relid;
$cliente = cataloghi_user_edit_get_cliente($uid);
$release = node_load($relid);
$form['cover'] = array(
'#title' => 'Carica la cover per la release '.$release->title,
'#description' => 'I file caricati devono avere estensione \'.jpeg\', risoluzione di 1440x1440 e dimensione massima di 5MB',
'#type' => 'managed_file',
'#upload_location' => 'public://clienti/'.$cliente->title.'/cover',
'#upload_validators' => array(
'file_validate_extensions' => array('jpeg, jpg'),
// Pass the maximum file size in bytes
'file_validate_size' => array(5*1024*1024),
'file_validate_image_resolution' =>array('1440x1440', '1440x1440'),
),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('CARICA'),
);
return $form;
}
function coverupload_form_submit($form, &$form_state) {
$file = file_load($form_state['values']['cover']);
// Change status to permanent.
$file->status = FILE_STATUS_PERMANENT;
// Save.
file_save($file);
$nodo = node_load($form_state['storage']['rid']);
$nodo->field_release_copertina['und'][0] = (array)$file;
if($nodo = node_submit($nodo)) { // Prepare node for saving
node_save($nodo);
}
}
All the forms have display: none, and when the user click on the cover upload button only the corresponding form is showed in the lightbox.
Well, everything works fine when the image is validated.
The problems start when the image is not validated (like if it's below 1440x1440px).
If I check the lightbox with the inspector, the correct number of forms is generated but they all refer to the same node (so they all have id 'coverup-17' for example).
I have checked everything, and it seems like I pass the correct values to the form everytime, so I'm starting to think that it may be a problem connected with my poor understanding of forms.
Would it be better to try a different type of approach?
Thanks and sorry for if this is a bit messy...
I managed to solve the problem.
It depended on the fact that I had multiple instances of the same form on the same page.
I implemented hook_forms().
function mymodule_forms($form_id, $args) {
$forms = array();
if(strpos($form_id, 'coverupload_form_') === 0) {
$forms[$form_id] = array(
'callback' => 'coverupload_form',
'callback arguments' => array($args[0], $args[1]),
);
}
return $forms;
}
and then I changed my form call to
drupal_render(drupal_get_form('coverupload_form_'.$relid, $arg1, $arg2));

Zend form in a popup (fancybox, lightbox....)

I am developping a web application using Zend and I ran out of ideas for a problem I am having. In just a few words, I am trying to have a contact form in a popup (Fancybox, lightbox, colorbox or whatever...). The whole thing works fine, in the sense that it shows up the contact form in the popup and allows to send emails. However, whenever there are errors (unfilled input or filled wrong), I couldn't get those errors to be displayed on the popup (it actually redirects me back to the form in a normal display (view+layout), to show the errors.
It is perhaps possible but I now thought that perhaps I could more easily bring my error message to a new popup (the contact page, filled unproperly, would lead to a error popup page...). I think this alternative could look cool but am having real trouble doing it. Now my real question is : Can we really make a form on a popup, using Facybox (Lighbox or any other actually ... just want my popup) and Zend? Any Guru outhere??
Thanks a lot
here is the code:
the link for instance:
<a class="popLink" href=" <?php echo $this->url(array('module'=>'default', 'controller'=>'contact', 'action'=>'sendmail')).'?ProID='.$this->proProfil->getProID(); ?>">Contact</a>
the action:
public function sendmailAction()
{
$this->_helper->layout()->setLayout('blank');
$request = $this->getRequest();
$proID = $this->_getParam("ProID");
$professionalsList = new Model_DirPro();
$proName = $professionalsList->getProInfo($proID);
$translate = Zend_Registry::get('translate');
Zend_Validate_Abstract::setDefaultTranslator($translate);
Zend_Form::setDefaultTranslator($translate);
$contactform = new Form_ContactForm();
$contactform->setTranslator($translate);
$contactform->setAttrib('id', 'contact');
$this->view->contactform = $contactform;
$this->view->proName = $proName;
if ($request->isPost()){
if ($contactform->isValid($this->_getAllParams())){
$mailSubject = $contactform->getValue('mailsubject');
if ($contactform->mailattcht->isUploaded()) {
$contactform->mailattcht->receive();
//etc....
the form:
class Form_ContactForm extends Zend_Form
{
public function init ()
{
$this->setName("email");
$this->setMethod('post');
$this->addElement('text', 'mailsubject',
array('filters' => array('StringTrim'),
'validators' => array(), 'required' => true, 'label' => 'Subject:'));
$mailattcht = new Zend_Form_Element_File('mailattcht');
$mailattcht->setLabel('Attach File:')->setDestination(APPLICATION_PATH.'/../public/mails');
$mailattcht->addValidator('Count', false, 1);
$mailattcht->addValidator('Size', false, 8000000);
$mailattcht->addValidator('Extension', false,
'jpg,png,gif,ppt,pptx,doc,docx,xls,xslx,pdf');
$this->addElement($mailattcht, 'mailattcht');
$this->addElement('textarea', 'mailbody',
array('filters' => array('StringTrim'),
'validators' => array(), 'required' => true, 'label' => 'Body:'));
$this->addElement('submit', 'send',
array('required' => false, 'ignore' => true, 'label' => 'Send'));
$this->addElement('hidden', 'return', array(
'value' => Zend_Controller_Front::getInstance()->getRequest()->getRequestUri(),
));
$this->setAttrib('enctype', 'multipart/form-data');
}
}
I would suggest implementing AJAX validation. This would allow for the form to be verified before it is submitted. ZendCasts has a good tutorial on how to accomplish this: http://www.zendcasts.com/ajaxify-your-zend_form-validation-with-jquery/2010/04/
Ajax requests are handled via the contextSwitch action helper. You can to specify the various contexts an action needs to handle (xml or json) in the init method of the controller as follows:
public function init()
{
$this->_helper->contextSwitch()
->addActionContext('send-mail', 'json')
->initContext()
;
}
The request url should contain a "format=json" appended to the query string. This will execute the action and send the response in json format. The default behaviour of JSON context is to extract all the public properties of the view and encode them as JSON. Further details can be found here http://framework.zend.com/manual/en/zend.controller.actionhelpers.html
I found a "probably not the prettiest" working solution, it is to indeed use ajax as mentioned in the previous zendcast for validation to stop the real validation (preventdefault), process the data return the result and if everything's ok restart it.

Custom error message for input validators (using the array syntax)

ZF 1.11.2
I've tried most of the syntaxes. They didn't click.
$validators = array('product_name' => array('alnum'));
//...
$input = new Zend_Filter_Input($filters, $validators, $_POST);
How in the world do you set a custom error message for alnum with the syntax above? Using 'messages' => array('Not alnum!!')? Yeah, well... How? I must've tried 100 nested arrays.
Use the built in translator.
For example, configure the translator in your config file to use a simple array
; Translations
resources.translate.data = APPLICATION_PATH "/lang"
resources.translate.adapter = "Array"
resources.translate.options.scan = "directory"
resources.translate.options.disableNotices = "1"
This tells the Translate application resource plugin that you want to
keep your translations under APPLICATION_PATH/lang
use the Array adapter (simplest)
scan the translation directory for languages / locales
ignore errors about unknown translations (ie user preferes en_AU but you don't have a specific translation file for that language)
Now, create folders for any languages you want to support. At a minimum, you'll want application/lang/en. For example
application
lang
en
en_AU
en_US
In each language folder, create a translate.php file. This file will contain (and return) an array of key / value pairs for each translation. You can find the keys for each validator message in the validator class. Here's an example for the Alnum validator
<?php
// application/lang/en/translate.php
return array(
Zend_Validate_Alnum::NOT_ALNUM => 'Not alnum!!',
Zend_Validate_Alnum::INVALID => 'Not valid!!'
);
For all Zend validators, you can also use the %value% placeholder in your message, eg
Zend_Validate_Alnum::NOT_ALNUM => "'%value%' is not alpha-numeric"
If you are simply trying to change the validation messages for a form element, I have always done it like this (inside a class that extends Zend_Form):
$this->addElement('text', 'myTextField', array(
'label' => 'The Label',
'description' => 'The description for the field...',
'filters' => array(
'StringTrim',
// etc
),
'validators' => array(
array('NotEmpty', true, array(
'messages' => 'This field is required',
)),
array('AnotherValidator', true, array(
'messages' => 'Bad value',
)),
// etc
),
));
Are you saying that this didn't work? Or are you using your validator in a more general context, in which case #Phil Brown's (awesome!) answer will do the job.
Disabling the translator on the element will disable the translation of all the validator messages. It is not possible to use a translator on the form or element and overwrite just one validator message. When the element is validated the translator is injected to every validator. The validator will use the translator if it is set. Thereby the custom error message won't be used.
Zend_Validate_Abstract::_createMessage()
// $message is your custom error message
$message = $this->_messageTemplates[$messageKey];
if (null !== ($translator = $this->getTranslator())) {
// your custom error message gets overwritten because the messageKey can be translated
if ($translator->isTranslated($messageKey)) {
$message = $translator->translate($messageKey);
} else {
$message = $translator->translate($message);
}
}
I think it is only possible to use a custom error message by disable the translator on the element.
$element->setDisableTranslator(true)
Use setMessage and disable translator if you have one.
$alnum = new Zend_Validate_Alnum();
$alnum->setDisableTranslator(true);
$alnum->setMessage(
'Not alnum!!',
Zend_Validate_Alnum::NOT_ALNUM
);
$validators = array('product_name' => array($alnum));
If you use your validator on a form element, you have to disable the translator on the element.