Can anyone advice how best to set a temporary variable with scope to be used between hooks?
I have a custom module with the purpose of checking and warning if an attempted file upload matches an existing file on the system.
I am using hook_form_alter to identify the specific upload form and hook_file_validate to check if the file was previously uploaded.
My problem is those two hooks don't share a common parameter - I need to pass information from hook_form_alter back to hook_validate.
The information I want the functions to share is a simple boolean which should be destroyed immediately the file upload is done/dismissed, so using variable_set to persist it to the database is overkill. I don't believe a session or cookie approach is best either.
UPDATES:
Globals approach:
function duplicate_uploads_warning_init(){
$GLOBALS['processed'] = 'testing';
}
function duplicate_uploads_warning_file_validate($file){
drupal_set_message("PROCESSED[file-validate]: {$GLOBALS['processed']}", 'warning');
}
function duplicate_uploads_warning_form_alter(&$form, &$form_state, $form_id){
if( $form_id == 'file_entity_add_upload' ){
drupal_set_message("PROCESSED[form-alter]: {$GLOBALS['processed']}", 'error');
$GLOBALS['processed'] = 'tested';
$form['#validate'][] = 'duplication_validate';
}
}
The code above sets GLOBALS[processed] in the init hook and that value in immediately confirmed in the hook_form_alter.
However the attempt to reassign the value to tested fails. The reassigned value is what I hoped to see in hook_file_validate but I still get the initial value of testing.
Hook_form_alter validation approach:
I tried adding a custom validation function but the upload of the image still took place where I intend to stop it. My code is as follows:
function duplication_validate($form, &$form_state) {
$data = duplicates($form_state['complete form']['upload']['#file']->filename);
if( sizeof($data) > 0 ){
form_set_error('test', 'testing validation');
return false;
}
}
I can confirm my $data variable has content and the sizeof test returns greater than 0.
using variable_set to persist it to the database is overkill
I don't agree they are overkill (you can easily delete variables), and as #2pha have mentioned globals are not recommended. I think you could use variable_set($name, $value), variable_get($name), and variable_del($name) without worrying unless you need to super-optimise your sites database queries. If you really don't want to use the variable_* functions, then maybe cache_set() and cache_get() might work because you can give it a temporary status.
Edit, variables approach:
function duplicate_uploads_warning_init(){
$account = \Drupal::currentUser();
variable_set($account->id() . '_processed', 'testing');
}
function duplicate_uploads_warning_file_validate($file){
$account = \Drupal::currentUser();
$processed_var = variable_get($account->id() . '_processed');
drupal_set_message("PROCESSED[file-validate]: {$processed_var}", 'warning');
}
function duplicate_uploads_warning_form_alter(&$form, &$form_state, $form_id){
if( $form_id == 'file_entity_add_upload' ){
$account = \Drupal::currentUser();
$processed_var = variable_get($account->id() . '_processed');
drupal_set_message("PROCESSED[form-alter]: {$processed_var}", 'error');
variable_set($account->id() . '_processed', 'tested');
$form['#validate'][] = 'duplication_validate';
}
}
… and in a success or #submit callback function run variable_del($account->id() . '_processed') to delete the variable.
maybe $GLOBALS['processed'] was initialized with the static keyword elsewhere....?
Related
I'm developing a Wordpress theme and I'm trying to store some of my variables in a function to re-use it among my theme files, without writing the same variables hundreds of time and without make them global. I've read that's a bad practice.
For now I'm using add_action but without results. Having in my functions.php
add_action( 'run_pms_variables', 'pms_variables_function' );
function pms_variables_function ($uid ) {
$the_group_uid = isset($_COOKIE["v_group_id"]) && !empty($_COOKIE["v_group_id"]) ? trim(strip_tags($_COOKIE["v_group_id"])) : "";
$session_detail = vpb_get_the_user_detail($uid);
$session_username = strlen($session_detail[0]) > 40 ? ucfirst(substr($session_detail[0],0,40)) : ucfirst($session_detail[0]);
$session_uid = $session_detail[1];
$session_email = $session_detail[2];
$session_photo = $session_detail[3];
$session_country = $session_detail[4];
//$session_usernames = explode(' ', $session_detail[0]);
$session_firstname = get_user_meta($uid,'first_name', true );
$session_lastname = get_user_meta($uid,'last_name', true );
}
and using eventually in my files like:
do_action('run_pms_variables', $uid );
I mean, can you address me to the right method? Thanks.
Write a class, declare a global object of that class, save all your variables as attribute/property of that class.
Now from anywhere just get the global object.
You have all variables stored inside that.
Uuuuhmm you are mixing apples with peaches. The WordPress Hooks, Actions and Filters are ment to modify the WordPress core the way you want, it is not build to store any data somewhere in your template.
One way to do it would be to simply store the values in the database of your WordPress installation. To do that you need to get familiar with the "Nonce" function, which is security mechanism for storing stuff in the database of WP.
There are hundrets and thousands of tutorials out there which show how to do it.
If you want only to store some numeric values or short strings, you could use the HTML data-* object to store some data, when php spits it back.
add_action( 'run_pms_variables', 'pms_variables_function' );
function pms_variables_function ($uid ) {
class GlobalVariables{
function __construct ($uid){
$this->the_group_uid = isset($_COOKIE["v_group_id"]) && !empty($_COOKIE["v_group_id"]) ? trim(strip_tags($_COOKIE["v_group_id"])) : "";
$this->session_detail = vpb_get_the_user_detail($uid);
$this->session_username = strlen($session_detail[0]) > 40 ? ucfirst(substr($session_detail[0],0,40)) : ucfirst($session_detail[0]);
$this->session_uid = $session_detail[1];
$this->session_email = $session_detail[2];
$this->session_photo = $session_detail[3];
$this->session_country = $session_detail[4];
//$session_usernames = explode(' ', $session_detail[0]);
$this->session_firstname = get_user_meta($uid,'first_name', true );
$this->session_lastname = get_user_meta($uid,'last_name', true );
}
}
return GlobalVariables($uid);
}
//and to access:
$global_variables = do_action('run_pms_variables', $uid );
echo $global_variables->the_group_uid;
As a side note, be definition global variables are variables that can be accessed anywhere, other options include setting variables in the $_SESSION super global (as most of you're variables look session specific) inside the pms_variables_function instead of setting class attributes.
This is from inside my Wordpress plugin, inside the main file:
function my_plugin_install() {
$my_site_url = get_site_url();
$my_options['my_site_url'] = $my_site_url;
// Save
}
register_activation_hook(__FILE__, 'my_plugin_install');
Currently, the install is successful but the 'my_site_url' option is not saved. I'm assuming because the way I'm using the $my_options array at this point doesn't mean anything. It should save this data to the wp_options table.
I can't seem to get this to save, or even find a way to test this as using "echo" gives Wordpress an error during install. Is there a best method for running a script and updating the database during install?
Thanks in advance.
You need to use the WordPress function update_option to save your option value:
function my_plugin_install() {
$my_site_url = get_site_url();
update_option('my_site_url', $my_site_url);
}
register_activation_hook(__FILE__, 'my_plugin_install');
And then later, when you need that value, you can use get_option:
$my_site_url = get_option('my_site_url');
*UPDATE
Since it appears you want to manage multiple of your own options, then I suggest using a simple "utility" function, like so:
function update_my_option($key, $value) {
// Load all of the option values from wp_options
$all_options = get_option('my_options');
// Update just the one option you passed in
$all_options[$key] = $value;
// Save to wp_options
update_option('my_options');
}
And, an appropriate getter function:
function get_my_option($key, $default = NULL) {
// Load all of your options from wp_options
$all_options = get_option('my_options');
// Return just the one option you are asking for
return (isset($all_options[$key])) ? $all_options[$key] : $default;
}
Then, rather than calling update_option directly, you'll call this function, as illustrated below:
function my_plugin_install() {
$my_site_url = get_site_url();
update_my_option('my_site_url', $my_site_url);
}
And, to get one of your options:
$my_site_url = get_my_option('my_site_url');
I have a function that processes sales via a third-party service, processes the result and returns an array with the Status "Success" or "Invalid." This sales call is made using the gform_after_submission hook applied to the specific form.
What I need to do is store the "Success" or "Invalid" result in the array as a variable that I can later pass to a function to validate or invalidate the credit card field, using gform_validation hook.
I'm declaring the variable in a function, like so:
function foo {
...code to sell product through API...
$status = $checkoutShoppingCartRequest['Result']['Status'];
}
When I print the variable $status within the function, it is showing either Success or Invalid like it should.
Here is other function where I need to use this variable, passed to gform_validation, which fails every time regardless of Success or Invalid result:
function MBvalidate( $validation_result ) {
$form = $validation_result['form'];
if ( $status !== "Success") {
$validation_result['is_valid'] = false;
foreach( $form['fields'] as &$field ) {
if ( $field->id == '34' ) {
$field->failed_validation = true;
$field->validation_message = 'Your credit card could not be processed.';
break;
}
}
}
//Assign modified $form object back to the validation result
$validation_result['form'] = $form;
return $validation_result;
}
add_filter( 'gform_validation_47', 'MBvalidate' );
I have tried passing the variable a number of different ways, via globals and sessions, etc.
I am new to GF development so I am sure I'm missing something. I'd appreciate any direction.
The gform_after_submission action hook runs after gform_validation.
Anyway, assuming you can find a hook that runs earlier, what I would do is store a unique variable for each submitted form using the Transients API's set_transient() and get_transient() functions. For example you can create a hidden field in every form which you populate with a random ID. Use this random ID as a key to store and retrieve the Success/Invalid result.
$status here is a local variable which has never been defined before you try to use it in if-condition. So, it's always null.
Maybe you missed
$status = $validation_result['Result']['Status'];
or something like this before checking the condition.
I have a form (defined in XML) which is used with Joomla's JForm to handle. What I'd like to know is if it's possible to validate against multiple rules at once.
Typically, I've come to understand that Joomla's JForm accepts only one rule for validation, defined in the XML of the form:
Joomla's JForm internals also seem to suggest I can't, the following area being the only one I can find handing validation:
// Get the field validation rule.
if ($type = (string) $element['validate'])
{
// Load the JFormRule object for the field.
$rule = $this->loadRuleType($type);
// If the object could not be loaded return an error message.
if ($rule === false)
{
throw new UnexpectedValueException(sprintf('%s::validateField() rule `%s` missing.', get_class($this), $type));
}
// Run the field validation rule test.
$valid = $rule->test($element, $value, $group, $input, $this);
// Check for an error in the validation test.
if ($valid instanceof Exception)
{
return $valid;
}
}
This isn't wrapped in a loop, so I'm quite concerned that I can't apply multiple rules at once to a particular field.
Are you looking for server or client side validation? Sean's answer seems to cover server side so I figured I'd add some insight into client side techniques.
You enable client side validation two ways. The first and simplest would be by adding the following to your form field definition, which would ensure any required fields are filled out to proceed.
required="true"
Second would be to add a class to the form field definition to let Joomla core know you want to validate the field and how. Joomla offers 4 validations built into the core: validate-username, validate-password, validate-numeric and validate-email.
These in and of themselves don't help you much, but the ability to create and reference custom client-side validations does. For my example we're going to ensure a check box is marked before allowing the form to submit. So in the form field definition I'll add:
class="validate-checked"
On the page where you render the form, be sure to load the JS library for validation using:
JHtml::_('behavior.formvalidation');
In addition, add the class form-validate to your form HTML element.
Add this javascript to handle the actual validation, here I have a checkbox input type with an ID of tos I'm verifying. In the setHandler method, the first parameter is the custom name I entered in the form field definition class statement, validate-checked:
<script>
window.addEvent('domready', function(){
document.formvalidator.setHandler('checked', function(value) {
var tos = document.getElementById('tos');
if (tos.checked) {
return true;
} else {
return false;
}
});
});
</script>
Now, capture the submit event and verify all core and custom validations passed before submitting the form.
Joomla.submitbutton = function(task) {
if (task == 'user.cancel' || document.formvalidator.isValid(document.id(".myFormId"))) {
Joomla.submitform(task, document.getElementById('myformId'));
}
You can create as many custom client-side validation scripts as you want. Inside the setHandler method you can interact with the DOM and use the passed in value parameter to determine if the field should pass, only needing to worry about returning true or false to indicate results and Joomla will handle the rest. So you can either create one complicated validation or many smaller concise validations to suit your needs.
Hope that helps...
This is a common request. There are a few possibilities. You could write your own JFormRule with more complex validation. The other is that you could programatically add an attribute to the field that runs the additional validation sort of like what Sean is advocating.
This answer assumes that it is not possible to natively add multiple rules on one field.
Assuming that it is not possible to apply multiple rules to one field natively, then it may be possible to extend JForm::validateField() to enable such a feature by simply calling the validate method for each validation rule found.
// Extending class JForm
protected function validateField(SimpleXMLElement $element, $group = null, $value = null, JRegistry $input = null) {
if($type = (string) $element['validate'])
{
$multiple_types = explode('|', $type);
if(is_array($multiple_types) && $multiple_types[0] !== $type)
{
foreach($multiple_types as $single_type)
{
$result = parent::validateField($element, $group, $value, $input);
// Validation failed, return the result and stop validating.
if($result !== true)
{
return $result;
}
}
return true;
}
else
{
return parent::validateField($element, $group, $value, $input);
}
}
}
With that example, validation rules could be structured like:
validate="rule1|rule2"
Drupal 7. Webforms 3.x.
I am trying to modify a webform component value on submit. I made a custom module called 'mos' and added this code to it.
function mos_form_alter(&$form, $form_state, $form_id) {
if ($form_id == 'webform_client_form_43') {
dsm($form['#node']->{'webform'}['components']['1']);
$form['#submit'][] = 'mos_contact_us_submit';
}
}
function mos_contact_us_submit($form, &$form_state) {
$form['#node']->{'webform'}['components']['1'] = 'working#mos.com';
}
However when I look at the results in the database the regular, non-overridden value is stored. Can you help let me know what I am doing wrong?
Eventually I want to take the input value and output an email address based on what was provided (for example. 24 turns into bob#somewhere.com) But I think I can figure this part out myself.
You should to place your submit first.
array_unshift(
$form['actions']['submit']['#submit'],
'mos_contact_us_submit'
);
However, if you want to change some variables in form_state, you should to using custom _valadate function.
I got it! BIG Thanks to #dobeerman for pointing me in the right direction. Here is the code that ended up working:
function mos_form_alter(&$form, &$form_state, $form_id) {
if ('webform_client_form_43' == $form_id) {
//dsm($form);
$form['#validate'][] = 'mos_check_email';
}
}
function mos_check_email(&$form, &$form_state, $form_id) {
$emailVal = $form_state['values']['submitted']['to'];
switch($emailVal) {
case 1: $emailVal = 'email#test.com'; break;
case 2: $emailVal = 'email2#test.com'; break;
case 3: $emailVal = 'email3#test.com'; break;
......
}
$form_state['values']['submitted']['to']=$emailVal;
//dpm($form_state);
}
This way I can keep email address private, but still pass variables to the form with _GET. Kind of a weird situation... but we are trying to keep some existing code intact, so it seemed like the best route.
I accidentally messed up my account creation, so I can't give you the credit dobeerman but I emailed the admins and hopefully I will get it straightened out to get you some rep!