Combining MIGX TVs without losing content

We have a site using MIGX. It’s been up and running a while. It has 3 different MIGX calls on various pages, each with its own TV & own set of Form names & Form Tabs. No problems there.

It’s just one of these situations where after we’ve built it and given to the client, we realise it would have been far easier and would have made more sense just to have all Form Names in one MIGV TV. The client could then drag and reorder any item on the page in a single Migx call. As it is we have 3 MIGX TVs, so the can only reorder on the page within that individual MIGX call, but of course each MIGX is called in turn in a fixed place in the resource template

Is it possible to combine existing MIGX TVs with their form names and formtabs into one MIGX TV WITHOUT losing any content of the existing TVs? I guess the answer is ‘no’ but there are very clever people on this forum who may know … so thought I’d ask.

Modx Revo 2.7.3 - Migx 2.11.0
Ubuntu 18 - PHP 7.2

It is definitely possible, but you have to write your own script to do it. MIGX stores the data as JSON, so you basically have 3 arrays of associative arrays that you have to combine somehow.

What exactly do you mean by “Form names”? The fields?

Hey Harry!

Form names which appear as a dropdown in the ‘Add Item’ Migx and are declared in the JSON such as:

[{
“formname”:“ImageTextBox”
,“formtabs”: [{
“caption”:“Content”
,“fields”: [{
“field”:“cell_1_image”
,“caption”:“Image”
,“inputTVtype”:“image”

etc, etc

So we’re looking to combine all the various FormNames, their formtabs and fields from the differnet Migxs into one Migx TV, so they are all available in one Migx call via the dropdown when the user clicks ‘Add Item’.

Here is a simple example:

Let’s say I have a MIGX-TV (ID=1) with this structure

[{
    "formname":"Form 1"
    ,"formtabs": [{
        "caption":"Tab A"
        ,"fields": [{
            "field":"a1"
            ,"inputTVtype":"text"
        }]
    }]
}]

and a second one (ID=2) with this structure

[{
    "formname":"Form 2"
    ,"formtabs": [{
        "caption":"Tab B"
        ,"fields": [{
            "field":"b1"
            ,"inputTVtype":"text"
        }]
    }]
},
{
    "formname":"Form 3"
    ,"formtabs": [{
        "caption":"Tab C"
        ,"fields": [{
            "field":"c1"
            ,"inputTVtype":"text"
        }]
    }]
}]

To combine them, I first have to create a new TV (ID=3) that combines the 2 structures:

[{
    "formname":"Form 1"
    ,"formtabs": [{
        "caption":"Tab A"
        ,"fields": [{
            "field":"a1"
            ,"inputTVtype":"text"
        }]
    }]
},
{
    "formname":"Form 2"
    ,"formtabs": [{
        "caption":"Tab B"
        ,"fields": [{
            "field":"b1"
            ,"inputTVtype":"text"
        }]
    }]
},
{
    "formname":"Form 3"
    ,"formtabs": [{
        "caption":"Tab C"
        ,"fields": [{
            "field":"c1"
            ,"inputTVtype":"text"
        }]
    }]
}]

Then to copy the data, I have to create a snippet and execute it once:

<?php
//Read value of TV with ID 1 from Resource with ID 11
$tv1 = $modx->getObject('modTemplateVarResource',array('contentid' => 11,'tmplvarid' => 1));
$data1 = $modx->fromJSON($tv1->get('value'));

//Read value of TV with ID 2 from Resource with ID 22
$tv2 = $modx->getObject('modTemplateVarResource',array('contentid' => 22,'tmplvarid' => 2));
$data2 = $modx->fromJSON($tv2->get('value'));

//To make sure that each item has a unique ID, find the maximum ID in TV1
$max_id = 1;
foreach($data1 as $item1){
    if ($item1['MIGX_id'] > $max_id){
        $max_id = $item1['MIGX_id'];
    }
}

//Add items of TV2 to TV1
foreach($data2 as $item2){
    $max_id += 1;
    $item2['MIGX_id'] = $max_id; //Change the ID
    $data1[] = $item2; //Append to array
}

//Read TV with ID 3 from Resource with ID 33
$tvCombined = $modx->getObject('modTemplateVarResource',array('contentid' => 33,'tmplvarid' => 3));
if (!$tvCombined){
    //Create a new TV if it doesn't already exist
    $tvCombined = $modx->newObject('modTemplateVarResource');
    $tvCombined->set('contentid', 33); //set resource id
    $tvCombined->set('tmplvarid', 3); //set tv id
}
//assign the combined data and save the TV
$tvCombined->set('value',$modx->toJSON($data1));
$tvCombined->save();
1 Like

Many thanks for your time and this example. We’ll work through this and post back.

We’ve created the combined TV as you suggest. We’ve got various MIGX TVs on the same resource ID to combine, so what we’ll try and do is modify your snippet to pull TV ID1, TVID 2 all from the same resource ID and dump the content into the new TV ID on that resource.

Halftrainedharry,
Genius. Your code worked like a dream! Nice one :slight_smile:

In our case, we are always combining TV1 and TV2 from the same resource into a TV3 on the same resource, with the intension then to delete TV1 & 2. What we intend to do is create an array with all the resource IDs we want to do this on, and loop through your snippet passing each resource value in a foreach loop.
Thanks again

The finished code loops through an array of resources, & for each resource combines Migx TV1, TV2 and TV3 and outputting to a new ‘combined’ Migx TV in the same resource. Only thing is, TV1, 2 & 3 may or may not necessarily have any content in, so we need to check if the TV is empty and if not, also increment the Migx item IDs appropriately so they are all unique.

The code below works very well - adding the snippet to a blank resource to call it. No doubt there may be tidier ways of doing coding, but thanks again to halftrainedharry.

<?php

$resourceArray = array(
1025,
1026,
1027
);

foreach ($resourceArray as $resourceId)
{

//Read value of TV with ID 195 from Resource with ID $resourceId
$tv1 = $modx->getObject('modTemplateVarResource', array(
    'contentid' => $resourceId,
    'tmplvarid' => 195
));
if ($tv1)
{
    $data1 = $modx->fromJSON($tv1->get('value'));
}

//Read value of TV with ID 197 from Resource with ID $resourceId
$tv2 = $modx->getObject('modTemplateVarResource', array(
    'contentid' => $resourceId,
    'tmplvarid' => 197
));
if ($tv2)
{
    $data2 = $modx->fromJSON($tv2->get('value'));
    $data1 = $modx->fromJSON($tv1->get('value'));
}

//Read value of TV with ID 204 from Resource with ID $resourceId
$tv3 = $modx->getObject('modTemplateVarResource', array(
    'contentid' => $resourceId,
    'tmplvarid' => 204
));
if ($tv3)
{
    $data3 = $modx->fromJSON($tv3->get('value'));
}

//To make sure that each item has a unique ID, find the maximum ID in TV1
$max_id = 1;
if ($data1)
{
    foreach ($data1 as $item1)
    {
        if ($item1['MIGX_id'] > $max_id)
        {
            $max_id = $item1['MIGX_id'];
        }
    }
}

//Add items of TV2 to TV1 if we have a TV1, if not find the maximum ID in TV2
if ($data2)
{
    foreach ($data2 as $item2)
    {
        if ($data1)
        {
            $max_id += 1;
            $item2['MIGX_id'] = $max_id; //Change the ID
            $data1[] = $item2; //Append to array
        }
        else
        {
            $data1[] = $item2; //Append to array
            $max_id = $item2['MIGX_id'];
        }
    }
}

//Add items of TV3 to TV1 or 2 if they exist
if ($data3)
{
    foreach ($data3 as $item3)
    {
        if ($data1 || $data2)
        {
            $max_id += 1;
            $item3['MIGX_id'] = $max_id; //Change the ID
            $data1[] = $item3; //Append to array
            
        }
        else
        {
            $data1[] = $item3; //Append to array
            $max_id = $item3['MIGX_id'];
        }

    }
}

//Read combined MIGX TV with ID 231 from Resource with ID $resourceId
$tvCombined = $modx->getObject('modTemplateVarResource', array(
    'contentid' => $resourceId,
    'tmplvarid' => 231
));
if (!$tvCombined)
{
    //Create a new TV if it doesn't already exist
    $tvCombined = $modx->newObject('modTemplateVarResource');
    $tvCombined->set('contentid', $resourceId); //set resource id
    $tvCombined->set('tmplvarid', 231); //set tv id
}
//assign the combined data and save the TV
$tvCombined->set('value', $modx->toJSON($data1));
$tvCombined->save();

unset($data1, $data2, $data3, $max_id);
}

be aware, that if you have reordered the items of the first TV, the last item might not have the maximum MIGX_id

sorry, I’ve overseen this part:
if ($item1['MIGX_id'] > $max_id)

should be all good

Sorry, there’s a rogue line beginning “$data1” in the " if ($tv2) " clause, needs removing