update values in repeating group elements based on other repeating group previous and new values

chris.paschen

Chris Paschen
I have a repeating group where I need to change the value of several elements (setting a date field to the current or future date) based on the previous and current values of certain fields within the same repeating group item.

So basically:

if $newStatus is X and $origStatus is Y set the date
do that for several different status elements and date elements
repeat over the entire repeat group for this present main entry.

I presently have this for the process that needs to happen (which works properly for the first item in the repeating group):

PHP:
    $reviewType = $formModel->formData['ked_books_reviews_requests_49_repeat___type_raw'];

    $origData = $formModel->getOrigData();
    $origData = FArrayHelper::getValue($origData,0,new stdClass);
    $origStatus = $origData->ked_books_reviews_requests_49_repeat___status_raw;
    $origStatus = is_array($origStatus) ? $origStatus[0] : $origStatus;
    $newStatus = $formModel->formData['ked_books_reviews_requests_49_repeat___status_raw'];
    switch ($newStatus)
    {
        case "2": //assigned
            if ($origStatus == 1) //was waiting for assignment
            {
                //set the response by date
                $now = new DateTime();
                //set the date assigned
                $formModel->formData['ked_books_reviews_requests_49_repeat___date_assigned'] = $now->format('Y-m-d H:i:s');   
               
                //get the number of days to respond
                $db = JFactory::getDbo();
                $query = $db->getQuery(true);
                if ($reviewType == 2) {
                    $query->select('review_decline_timelimit');
                } else {
                    $query->select('review_decline_timelimit');
                }
                  $query->from($db->quoteName('ked_books_system_settings'));
                  $query->where("1");
                $db->setQuery($query);
                $hoursToRespond = (int)$db->loadResult();
                $responseDue = $now->modify('+'.$hoursToRespond.' hours');
                $formModel->formData['ked_books_reviews_requests_49_repeat___date_request_due'] = $now->format('Y-m-d H:i:s');   
            }
            break;
        case "7": //review published

            if (!($origStatus == 7))
            {
                //set the published date
                $now = new DateTime();

                //set the date published
                $formModel->formData['ked_books_reviews_requests_49_repeat___date_published'] = $now->format('Y-m-d H:i:s');   
            }
            break;
        }

I've reviewed the suggestions here:
http://fabrikar.com/forums/index.ph...-a-field-in-a-repeat-group.43315/#post-221171
However, I'm not sure what the proper syntax would be to get the $origData for each item.

Can you help 'translate' how to access those getOrigData lines so that they properly pull in the data for the repeating group?

NOTE: This is running on the onBeforeStore of the form.
 
Ah, you've hit on a tough one.

The original data is loaded using the list model's query. Which means it'll look like a list with repeat joins WITHOUT "merge rows" enabled. So if you have, say, one repeat group (we'll drill down into more than one in a minute) with 3 repeats, you'll have 3 rows in the origdata array ...

maintable___id, repeattable___id, repeattable___parent_id
1, 1, 1
1, 2, 1
1, 3, 1

That code you have does this:

Code:
   $origData= FArrayHelper::getValue($origData,0,new stdClass);

... so it just grabs the first row (1,1,1) with the first set of repeated data.

What surprises me is that you are doing:

Code:
   $newStatus=$formModel->formData['ked_books_reviews_requests_49_repeat___status_raw'];

... and you say it works for the first repeat. But because it's in a repeat, that formData element should be an array, with as many entries as you have repeats, so I'm surprised that works at all, as $newStatus should be an array.

Anyway ... what I would expect you to have to do is ...

Code:
forearch ($newStatus as $key => $status) {
   // your existing code, using $status instead of $newStatus, and using [$key] to index any other repeat group elements you access,
   // so you get the correct repeat instance of that element, like ...
   // $formModel->formData['ked_books_reviews_requests_49_repeat___date_assigned'][$key]=$now->format('Y-m-d H:i:s');
}

Then of course you have the problem of figuring out which row of $origData you need to match the repeat you are processing. Which isn't trivial, because you can't just use the $key of the element you are iterating with, i.e if you are on the second of the element's repeats, you can't assume you need the second row from orgidata ... because two reasons:

1) They may have deleted a repeat on the form, which means your keys won't match. If they deleted row 2, then index 2 in the submitted data will be the third row in origdata.

2) If you have more than one repeat on the form, then that origdata structure gets funky ... so say you have 2 repeat groups, with 3 repeats in each ...

maintable___id, repeattable1___id, repeattable1___parent_id, repeatable2___id, repeattable2___parent_id
1, 1, 1, 1, 1
1, 1, 1, 2, 1
1, 1, 1, 3, 1
1, 2, 1, 1, 1
1, 2, 1, 2, 1
1, 2, 1, 3, 1
1, 3, 1, 1, 1
1, 3, 1, 2, 1
1, 3, 1, 3, 1

... you have 9 rows, to represent that one row in the parent table. This makes more sense if you look at a list view with multiple repeat groups, with "Merge rows" turned off.

This isn't a Fabrik thing, this is a relation database thing, the result of doing ...

SELECT * FROM parent
LEFT JOIN child1 ON child1.parent_id = parent.id
LEFT JOIN child2 ON child2.parent_id = parent.id

... so the result set is (number of rows in main table * number of related rows in child1 * number of related rows in child2). And you can't just use the $key of your submitted repeat group, because it won't match that structure.

So ... to find the "matching" origdata, you'd have to iterate through the origdata, looking for the matching 'id' of the repeat you want. So you'd want ...

$formModel->formData['ked_books_reviews_requests_49_repeat___id'][$key]

... which gives you the PK (id) of that repeat, then iterate through the $origdata[] array, looking for the first occurence of ked_books_reviews_requests_49_repeat___id that matches it.

This kind of stuff is VERY non-trivial, and is kind of what makes Fabrik a bit magic, in that in normal operation, we hide all this stuff from you and just do it, and what we do behind the scenes gets mind numbingly complex. But when you need to customize stuff like this, it can get hairy unless you are very familiar with the data structures.

-- hugh
 
Last edited:
THANKS for that. It helps to know that I'm not making this harder than it is ... that it actually is hard to do!

I think the only 'reasonable' way (without me doing rocket science coding) is to just manually store the originalData into some system elements (so I have a 'lastValue' entry as well as the current value, and then move the functioning to onAfterStore and just iterate through the saved data and do my processing directly via db functioning in PHP - which is definitely possible with what I need to do.
 
We are in need of some funding.
More details.

Thank you.

Members online

Back
Top