9 years ago
Topic

I'm trying to understand best practices for using and storing data for Group X fields.

I have created a custom content type called "My Custom Widget" for storing the Group X fields. I have another custom type called "My Custom Article Type" and in this custom type I have created a custom Group X field called "Custom Widgets Group X" in which I am pulling the custom fields from the My Custom Widget custom type. 

The back end form for the My Custom Article Type works great - the user can replicate, delete, and edit the "Widgets" just fine. However, I am building a custom module that requires me to query the database to pull the data from these fields but the only data entered in the database is in in the introtext field of the article.

I've read the documentation on How to Manage Fields Storage but some details are still muddy. I need to find the best way to create these database columns but it's not clear what is the best way to do this. The documentation's statement below is not clear to me:

But it's not because the introtext field that uses this storage is preferred to store multiple fields here. therefore, do not use the column "introtext" to store your FieldX and GroupX fields. You can store them in other columns/databases, same as with Standard storage format.

My question is: How can I store Group X fields in another column or table instead of storing the data in the introtext?

Get a Book for SEBLOD
572 Posts
_jrmo
9 years ago
1
Level 1

Hi Daniel,

You can change the storage of field at the time that you create the field. At the bottom of field setup window, you will see the "storage" options. By default, for a Group_X field, this is the introtext column of the content table. However, you can add a new column to have the values stored by entering in a value here. So that the storage becomes Standard > Article > column_name.

Cheers,

James

9 years ago
0
Level 2

Thanks for you speedy response. I've got it working. I did create a new table through the group x. Took me a while to understand I could type in the mapped column to create a new column though the group x field - no sql script required. Very cool. Since I was pulling the group x data via a database call though a module that is positioned outside of the Seblod template, I had to create a crazy formatting function to get the groupx field data in JSON format. Everything is golden! Thanks for your help.

---------------------------

Here is a little tutorial on how I got here:

Summary

I needed to create a custom banner that allows an administrator to create a banner (we call Flex Banner) in an article showing multiple banners and each banner would have a title, description, link, and banner image. The admin should be able to delete and create additional banners dynamically with a limit of 10. This banner would be displayed outside and above the Seblod content area. Also, I would need extensive control of the markup. I decided that the best way to do this is to create a custom module and position it at full width in the page header section.

Step 1 

Create a custom type (I call flex_banner) and create the following fields:

  • Link (flex_banner_link)
  • Image (flex_banner_image)

Both fields are saved to use standard storage. For the image field, I checked the "advanced" box so I could pull the image's description and title.

Step 2

In the custom type (My Custom Article) that the administrator uses to manage their page content, I created a group x field and assign it to the custom type created in Step 1. The storage for this is set to custom and I mapped it to a new column called "flex_banner_groupx". 

Now the user can set up their banners in the back end and we can see how the database is storing the data. The _cck_store_form_my_custom_article table shows the flex_banner_groupx column and stores the data in funky seblod formatting. If you copy and paste this data in an editor, you can see it has a sort of nested format. In order to make use of this data, I needed to pull the data and parse it into JSON format. 

Step 3

Create a custom module and set the position desired. I'm not going into detail here but my advice to you is to make a basic hello world to see if you have it set up correctly. 

In the module's helper.php file I used two classes. One to query the database and the other to convert the data into JSON

	function customFlexQuery($select, $from) {
            // Get a db connection.
            $db = JFactory::getDbo();
            // Create a new query object.
            $query = $db->getQuery(true);
            $query->select($db->quoteName($query));
            $query->select($db->quoteName($select));
            $query->from($db->quoteName($from));
            $article_id = JFactory::getApplication()->input->get('id');
            $query->where($db->quoteName('id') . ' = ' . $article_id);
            // Reset the query using our newly populated query object.
            $db->setQuery($query);
            // Load the results as a list of stdClass objects (see later for more options on retrieving data).
            $results = $db->loadObject();
            //clean the query up to remove seblod's before and after tags in the field
            $custQuery = $results->$select;
            return $custQuery;
        }
        function replace_content_inside_delimiters($start, $end, $new, $source) {
            return preg_replace('#(' . preg_quote($start) . ')(.*?)(' . preg_quote($end) . ')#si', '$1' . $new . '$3', $source);
        }
        //convert text from flex_banner_groupx data in database and convert to valid json
        function getJsonData() {
            $flexSeblodData = customFlexQuery('flex_banner_groupx', 'x36w0_cck_store_form_program_page');
            $str1 = replace_content_inside_delimiters('flex_banner_image|', '|flex_banner_groupx', '', $flexSeblodData);
            $str2 = replace_content_inside_delimiters('flex_banner_link|', '|flex_banner_groupx', '', $str1);
            $str3 = str_replace('<br />', '', $str2);
            $str4 = replace_content_inside_delimiters('::flex_banner_groupx::', '::/flex_banner_groupx::', '', $str3);
            $str5 = str_replace('::flex_banner_groupx::::/flex_banner_groupx::', '{"flex_banner_groupx":{', $str4);
            $shrapnel = explode('::cck_flex_banner_groupx::flex_banner::/cck_flex_banner_groupx::', $str5);
            // add an incrementing number for each cck_flex_banner_groupx - 
            $newStr = '';
            $count = 0;
            for ($i = 0; $i < count($shrapnel); ++$i) {                
                if ($i == count($shrapnel) - 1) {
                    $newStr .= $shrapnel[$i];
                } else {
                    $newStr .= $shrapnel[$i] . '"cck_flex_banner_groupx_' . ++$count . '":{';
                }
            }
            $str6 = str_replace('::flex_banner_image||flex_banner_groupx::', '"flex_banner_image":', $newStr);
            $str7 = str_replace('::/flex_banner_image||flex_banner_groupx::', ',', $str6);
            $str8 = str_replace('::flex_banner_link||flex_banner_groupx::', '"flex_banner_link":', $str7);
            $str9 = str_replace('::/flex_banner_link||flex_banner_groupx::::cckend_flex_banner_groupx::::/cckend_flex_banner_groupx::', '},', $str8);
            $str10 = str_replace('::cckend_flex_banner_groupx::::/cckend_flex_banner_groupx::', '}', $str9);
            //remove the last comma
            $jsonFlex = strrev(implode(strrev(''), explode(',', strrev($str10), 2))) . "}}";
            //we have to convert json to an object by decoding it
            $flexObj = json_decode($jsonFlex, JSON_PRETTY_PRINT);
            return $flexObj;
        }

Then edit the module's default.php file to get the variables like so:

<div class="container">
    <div class="nuflex <?php echo getBannerType(); ?>">
        <ul>
<?php
$flexObj = getJsonData();
$flexBanner = $flexObj['flex_banner_groupx'];
$banner = '';
$counter = 0;
foreach ($flexBanner as $banner) {
    $counter++;
    $flexBannerTitle = $flexBanner['cck_flex_banner_groupx_' . $counter . '']['flex_banner_image']['image_title'];
    $flexBannerImage = $flexBanner['cck_flex_banner_groupx_' . $counter . '']['flex_banner_image']['image_location'];
    $flexBannerDesc = $flexBanner['cck_flex_banner_groupx_' . $counter . '']['flex_banner_image']['image_description'];
    $flexBannerLink = $flexBanner['cck_flex_banner_groupx_' . $counter . '']['flex_banner_link']['link'];
?>  
            <li>
                <div class="image" style="background-image: url('/<?php echo $flexBannerImage; ?>');"></div>
                <div class="caption">
                    <div class="content">
                        <h2><?php echo $flexBannerTitle; ?></h2>
                        <p><?php echo $flexBannerDesc; ?></p>
                        <a href="/<?php echo $flexBannerLink; ?>" class="btn btn-secondary">Read More</a>
                    </div> 
                </div>
            </li>
    <?php } ?>
        </ul>
    </div>
</div>

I hope others can benefit from what I've learned here. I know the parsing code is ugly. Let me know if you have any better ideas.

Get a Book for SEBLOD