Validations on repeat groups seem impossible

Bauer

Well-Known Member
I've been struggling for 3 days now trying to get some validations working in a form in a repeat group.
I thought I could work my way around the known problems (where the validation plugins are not tracking a RepeatCounter) by using the php validation plugin as has been recommended in other threads on this issue.

But my 'brainstorm' turned out to be more like a smelly fart.
In the form in question there is a databasejoin element with 4 options that trigger the display of a few other fields.

So my workaround for that (I thought) was to use the php validation plugin instead and write some code that would only run the validation rule if the index level of the element matched the appropriate 'trigger' value selected in the databasejoin element.

Because the {placeholder} returns all of the keys in the repeat group as an imploded (comma delimited) string, I thought I could just turn the placeholder values back into an array and match up the array indexes between the controlling database join element and the element I was validating.

For example here's the code used for one element in the repeat group. ( 'facility_type_id' is the database join element that triggers the show/hide of the other elements - and my debugging code is also included ) ...
PHP:
error_log ( 'facility_type: {fb_organizations___facility_type_id_raw}' );
error_log ( 'physician count: {fb_organizations___hospital_gross_income_raw}' );
$ftypes = array({fb_organizations___facility_type_id_raw});
$vals = array({fb_organizations___hospital_gross_income_raw});
$ok = true;
for ( $x=0; $x<count($ftypes); $x++ )
{
  error_log( (int)$ftypes[$x] . ':' . (int)$vals[$x] );
  // if facility_type_id is 1 then run this validation ( must be greater than 0 )
  if ( (int)$ftypes[$x] == 1 && (int)$vals[$x] < 1 ) $ok = false;
}
return $ok;
I thought that would solve my problem until I found that the {fb_organizations___hospital_gross_income_raw} placeholder was returning this in the error log...
facility_type: 1,2
hospital_gross_income: 54,765,477,0

I was expecting...
facility_type: 1,2
hospital_gross_income: 54765477,0

In that case facilty[0] (val 1) validates ok because hospital_gross_income[0] > 0
and facilty[1] (val 2) validates ok because I'm only concerned if the facility_id is 1

To explain what is happening here-
The actual facility_type values in the repeat tables are 1 & 2 (consecutively)
The actual hospital_gross_income values are 54765477 & 0 (consecutively)

BUT because I have the element set to 'numeric format' with thousands separator and zero decimals - when hospital_gross_income[0] and hospital_gross_income[1] are turned into a placeholder - {fb_organizations___hospital_gross_income_raw} became 54,765,477,0

UGHHH!
That means my validation would only work if the 1st repeat group has a facility_type of 1.

What if there were 4 repeat groups instead of 2 and the facility_types were entered in the order 4,2,3,1 instead of 1,2 - and the hospital Gross income was $54,000,477?
My code would then return...
facility_type: 4,2,3, 1
hospital_gross_income: 0,0,54,000,477
and the validation would fail because it would see $ftypes[3] as '000'
What a mess.

Also, this would only work if the field you are validating returns a single value - not a multiselect. In that case the placeholder would really get crazy because it just truncates all the values together into one long comma delimited string. How would you even know what set belonged to what repeat index?

I think we need to use something other than a comma here to separate the repeat group values, no? Or put each value set in brackets. So instead of a placeholder returning something like 5,6,8,2,4,5,9,5,3,2,45,32 - which takes a little work to figure it - it should return either 5,6,8|2,4,5|9,5,3|2,45,32 -or- [5,6,8],[2,4,5],[9,5,3],[2,45,32]

Another setback was discovering that for repeat group elements that had validation rules set -whether the elements are hidden or not, validation will be triggered on all of them at once - and all will show as invalid (in red), if even one fails the validation rule. Talk about confusing to the end-user.

I went so far as to write some javascript to toggle the 'disabled' attribute of the element in the DOM for the hidden inputs as appropriate - but the ajax validation is still triggered on every element in the repeat group even if the element has been disabled via javascript.

Until there is a way to handle validation in repeat groups I'm pretty much stuck with doing it all via javascript, I guess.

What is the timetable for fabrik v4 alpha?:(
 
Well, ya coulda just asked. I've added $repeatCounter to the _eval() method's args in the PHP plugin, so it's now available to your code.

https://github.com/Fabrik/fabrik/commit/41acc0297b77c37934373abd063e47637dc98c16

And rather than using placeholders, which were never really designed to handle repeat groups - for exactly the reasons you just discovered - use $formModel->formData[] directly. So, for instance ...

$formModel->formData['fb_organizations___facility_type_id_raw']

... assuing I read your post correctly, and is an element in the repeated joined data, should be an array, indexed by repeat count, with all of the repeated data in it. So ...

$formModel->formData['fb_organizations___facility_type_id_raw'][$repeatCounter]

... would be the facility_type_id for the repeat instance your element with the validation on it is in. And which (if it's a join) will probably be an array itself.

So you should now be able to do what you need to do, without any farting around.

Regarding ...

Another setback was discovering that for repeat group elements that had validation rules set -whether the elements are hidden or not, validation will be triggered on all of them at once - and all will show as invalid (in red), if even one fails the validation rule.

I can't replicate that. Here's a quick video, with the validation set to fail is $repeatCounter is 1, just as a silly example, but it shows a) $repeatCounter is now available for the code, and b) only the repeat which failed is marked as having failed.

http://screencast.com/t/3geYpmzt36

With regards to whether elements are visible or not, and validations running / not running ... we had a Long Think about this, and decided to leave that up to the develeoper, through using the Condition. Several reasons, to do with not making assumptions about what the developer may or may not want to do, and also "hideen" is not something which gets passed in with the form's submitted data, so it would have required quite a lot of code to add that.

So, if you have some "controlling" element which hides / shows groups or elements, and you don't want to validate if they are hidden ... you need to test that yourself in the Condition code for the validation. And, just becaus eI'm Such A Nice Guy, I just added $repeatCounter to the shouldValidate() method as well, so it's available to your Condition code. :)

https://github.com/Fabrik/fabrik/commit/86c71bbce786d4d01cf28584a1794fb731f78d4b

Let me know if you have any more issue. I'll try and keep an eye out for this thread, but as usual, I can't guarantee it, if I'm having a busy day with paid support. So feel free to drop me some gmail if I don't respond.

-- hugh
 
Ooops, thought I had the mic on for that video, but apparently not. So just supply your own sound track, with me saying all sorts of informative stuff about what's going on.

-- hugh
 
This is a refreshing reply to wake up to. It sounds like you've addressed most of my problems. Just updating from github now and will let you know how it goes.
Thanks much.:)
 
OK - That works - and I get it now.:D

While I might have your ear...
One thing I did come across while using my debugging code for this issue is just what triggers this error that I have mentioned numerous times before....
Backtrace from warning 'Undefined variable: repeatCounter' at /home/public_html/plugins/fabrik_element/databasejoin/databasejoin.php 3114:

I always just assumed that the error occurs because that function is not being passed the $repeatCounter and yet references it. I've pointed that out many times yet could never pinpoint what triggered a call to that function to begin with.

Now I know. This happens when the element is a display element - and so there is a label, but no value to get. (There is another easily fixed error triggered by display elements listed below.) It's one of those errors that is more of an annoyance than anything else - yet it could be 'fixed' by surrounding the code that throws the error with an if condition.

So while I'm talking about simple error fixes - I'll repost this list of fabrik errors that will clutter the php error log with thousands of entries - yet could all be fixed in 10 minutes.

I must make all these changes EACH TIME I update from github - if for no other reason than the sake of my sanity - because it just bugs the heck out of me to see them repeated thousands of times in a matter of an hour or so.

Backtrace from warning 'Undefined property: stdClass::$data' at /home/public_html/components/com_fabrik/views/list/tmpl/bootstrap/default_row.php 20:
Backtrace from warning 'Trying to get property of non-object' at /home/public_html/components/com_fabrik/views/list/tmpl/bootstrap/default_row.php 20:

Change line 20 in components/com_fabrik/views/list/tmpl/bootstrap/default_row.php from
PHP:
<?php echo @$this->_row->data->$heading;?>
to
PHP:
<?php echo (isset($this->_row->data->$heading)) ? $this->_row->data->$heading : '';?>
-----------------------
Backtrace from warning 'Undefined property: PlgFabrik_ElementYesno::$tmpl' at /home/public_html/plugins/fabrik_element/yesno/yesno.php 75: /home/compcirc/public_html/index.php 40:

Change line 75 in plugins/fabrik_element/yesno/yesno.php from
PHP:
$displayData = array('value' => $thisRow->$raw, 'tmpl' => @$this->tmpl);
to
PHP:
$displayData = array('value' => $thisRow->$raw, 'tmpl' => (isset($this->tmpl)) ? $this->tmpl : '');
-----------------------
Backtrace from warning 'Undefined property: JForm::$repeatCounter' at /home/public_html/administrator/components/com_fabrik/models/fields/fabrikmodalrepeat.php 55:

Change line 55 in administrator/components/com_fabrik/models/fields/fabrikmodalrepeat.php
PHP:
$subForm->repeatCounter = (int) @$this->form->repeatCounter;
to (not sure on this ?should be initialized as 0 or null?)
PHP:
$subForm->repeatCounter = isset($this->form->repeatCounter) ? (int) $this->form->repeatCounter : 0;
-----------------------
Then there is this error that will occur when in form view - which will be replicated for every element that is either hidden or has no input 'value' (e.g. using the display plugin)

Backtrace from warning 'Undefined index: fb_organizations___include_management' at /home/public_html/components/com_fabrik/models/form.php 2123:
Backtrace from warning 'Undefined index: fb_organizations___include_management' at /home/public_html/components/com_fabrik/models/form.php 2124:
Backtrace from warning 'Undefined index: fb_organizations___facility_details_header' at /home/public_html/components/com_fabrik/models/form.php 2123:
Backtrace from warning 'Undefined index: fb_organizations___facility_details_header' at /home/public_html/components/com_fabrik/models/form.php 2124:
Backtrace from warning 'Undefined index: fb_organizations___practice_specialties' at /home/public_html/components/com_fabrik/models/form.php 2123:
Backtrace from warning 'Undefined index: fb_organizations___practice_specialties' at /home/public_html/components/com_fabrik/models/form.php 2124:
Backtrace from warning 'Undefined index: fb_organizations___survey_link' at /home/public_html/components/com_fabrik/models/form.php 2123:
Backtrace from warning 'Undefined index: fb_organizations___survey_link' at /home/public_html/components/com_fabrik/models/form.php 2124:

This one can be eliminated by inserting this line
PHP:
if( !isset($post[$elName2]) ) continue;
at line 2117 of components/com_fabrik/models/form.php

This short-list might seem trivial but some users may become really annoyed or made skeptical of your code because of any errors generated - so I think the 10 minutes would be time well spent.
Thank you again for the attention. :)
 
OK, think I fixed that line 3114 thing in the database join:

https://github.com/Fabrik/fabrik/commit/875e90d932756f43bdf69769f72d45be501c1883

Did you ever watch that video I sent you of how to fork Fabrik, make a change and submit a PR on our code in < 2 minutes, without leaving the comfort of the github site, no software installation or special knowledge required? Which will then put your PR in a queue where others can review / test the code, that we regularly check, and we can merge your request by just pushing a button?

-- hugh
 
We are in need of some funding.
More details.

Thank you.

Members online

No members online now.
Back
Top