We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 24676
    • 60 Posts
    Hi

    I am hoping someone can help. I have created a couple of custom tables which have a many to many relationship. I have a third table handling the relationships. My schema is below.

    <?xml version="1.0" encoding="UTF-8"?>
    <model package="products" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1">
      <object class="ProductInfo" table="product_infos" extends="xPDOSimpleObject">
        <field key="name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
        <index alias="PRIMARY" name="PRIMARY" primary="true" unique="true">
                    <column key="id" collation="A" null="false" />
            </index>
        <composite alias="ProductsApplicaton" class="productApplication" local="id" foreign="product" cardinality="many" owner="local" />
      </object>
      
      <object class="Application" table="applications" extends="xPDOSimpleObject">
        <field key="application" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
        <index alias="PRIMARY" name="PRIMARY" primary="true" unique="true">
                    <column key="id" collation="A" null="false" />
            </index>
        <composite alias="ProductsApplication" class="productApplication" local="id" foreign="application" cardinality="many" owner="local" />
      </object>
      
      <object class="ProductApplication" table="product_applications" extends="xPDOSimpleObject">
        <field key="product" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default="0" index="index" />
        <field key="application" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default="0" index="index" />
        <index alias="PRIMARY" name="PRIMARY" primary="true" unique="true">
                    <column key="id" collation="A" null="false" />
            </index>
        <aggregate alias="Product" class="ProductInfo" local="product" foreign="id" cardinality="one" owner="foreign" />
        <aggregate alias="Application" class="Application" local="application" foreign="id" cardinality="one" owner="foreign" />
      </object>
      
    </model>



    I am using MIGXdb to handle the CMP side of things. I can set up separate CMPS to add data to my two databases but what is the best way to handle creating the relationships?

    Do I need to create a third CMP with drop down lists and link them up? I can't see how this way would work?

    Many thanks in advance!

      • 4172
      • 5,888 Posts
      you can add a listbox-multiple-field with @EVAL, @SELECT or @CHUNK - binding in inputOptionValues to get the items into the listbox

      Than have a custom update-processor, which handles to syncronize the selected values with the connection-table.

      Another way (if you have many items) , what I did several times is to have another searchable/filterable MIGXdb - grid inside where you can select the items for connection directly.
        -------------------------------

        you can buy me a beer, if you like MIGX

        http://webcmsolutions.de/migx.html

        Thanks!
        • 24676
        • 60 Posts
        Hi Bruno - Many thanks for your fast reply.

        I have managed to add a listbox which is working great. so half way there! I am a little lost with a custom processor so I think I am gonna have to find a tutorial to work through that one. I will take a look at nested MIGdb as well - sounds like it could be a useful solution.

        I may be misunderstanding things here but is there a way of pulling in the name of my product from the id of my relationship table. So for example if I create a CMP for my relationship table in the grid i just see id numbers but I want to see the associated names they are related to. (ie as a join).

        Hope that makes sense.
          • 4172
          • 5,888 Posts
          in the MIGXdb - settings there is a field named 'joins'

          put

          [{"alias":"Product"},{"alias":"Application"}]


          into it.

          Than you can use Product_name and Application_application as field-names in the columns-definition
            -------------------------------

            you can buy me a beer, if you like MIGX

            http://webcmsolutions.de/migx.html

            Thanks!
            • 24676
            • 60 Posts
            It works like a dream and is exactly what I was after Being unable to create joins was causing a lot of my problems.

            Just out of interest do you know of or have any examples of using a custom processor to add multiple relationships via a listbox-multiple field?
              • 4172
              • 5,888 Posts
              I have examples.
              Need to search for them.
                -------------------------------

                you can buy me a beer, if you like MIGX

                http://webcmsolutions.de/migx.html

                Thanks!
                • 24676
                • 60 Posts
                Hi Bruno

                I have a bit more of a clear idea what I am wanting to achieve now and I am hoping you can point me in the right direction.

                How do I go about having a searchable/filterable MIGXdb grid inside my products CMP. So i can loop through and list multiple applications (in my schema) and list them all/add new all within my individual products. I can't see how that relationship works. I suspect my schema isn't correct, but I am going round in circles with it.
                  • 24676
                  • 60 Posts
                  Sorry to bombard - but I have managed to get a little further and to be honest I think I am nearly there.

                  I managed to nest a grid (applications) inside another (products). I can load the grid but it is blank and is not pulling any of the relevant fields in. Clearly I am missing a relationship somewhere but to be honest I am finding my way via trial and error rather than any great logic.

                  My schema is the same as at the start of this thread.

                  Thanks in advance!
                    • 4172
                    • 5,888 Posts
                    first, here is a solution, which seems to work to get listbox-multiple-items to your connection-table.

                    There was some typos in your schema, so I post it here again:
                    [note] I've changed the packagename to migxproducts! You need to change that back, also in the MIGX - configuration, I've posted

                    <?xml version="1.0" encoding="UTF-8"?>
                    <model package="migxproducts" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1">
                      <object class="ProductInfo" table="product_infos" extends="xPDOSimpleObject">
                        <field key="name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
                        <index alias="PRIMARY" name="PRIMARY" primary="true" unique="true">
                                    <column key="id" collation="A" null="false" />
                            </index>
                        <composite alias="ProductsApplication" class="ProductApplication" local="id" foreign="product" cardinality="many" owner="local" />
                      </object>
                       
                      <object class="Application" table="applications" extends="xPDOSimpleObject">
                        <field key="application" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
                        <index alias="PRIMARY" name="PRIMARY" primary="true" unique="true">
                                    <column key="id" collation="A" null="false" />
                            </index>
                        <composite alias="ProductsApplication" class="ProductApplication" local="id" foreign="application" cardinality="many" owner="local" />
                      </object>
                       
                      <object class="ProductApplication" table="product_applications" extends="xPDOSimpleObject">
                        <field key="product" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default="0" index="index" />
                        <field key="application" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default="0" index="index" />
                        <index alias="PRIMARY" name="PRIMARY" primary="true" unique="true">
                                    <column key="id" collation="A" null="false" />
                            </index>
                        <aggregate alias="Product" class="ProductInfo" local="product" foreign="id" cardinality="one" owner="foreign" />
                        <aggregate alias="Application" class="Application" local="application" foreign="id" cardinality="one" owner="foreign" />
                      </object>
                       
                    </model>
                    



                    this is my setup:

                    {
                      "formtabs":[
                        {
                          "MIGX_id":26,
                          "caption":"product",
                          "print_before_tabs":"0",
                          "fields":[
                            {
                              "MIGX_id":182,
                              "field":"applications",
                              "caption":"",
                              "description":"",
                              "description_is_code":"0",
                              "inputTV":"",
                              "inputTVtype":"listbox-multiple",
                              "validation":"",
                              "configs":"",
                              "restrictive_condition":"",
                              "display":"",
                              "sourceFrom":"config",
                              "sources":"",
                              "inputOptionValues":"@EVAL return $modx->runSnippet('migxLoopCollection',array('packageName'=>'migxproducts','classname'=>'Application','tpl'=>'@CODE:[[+application]]==[[+id]]','outputSeparator'=>'||'));",
                              "default":"@EVAL return $modx->runSnippet('getProductApplicationList');",
                              "pos":1
                            },
                            {
                              "MIGX_id":180,
                              "field":"name",
                              "caption":"Name",
                              "description":"",
                              "description_is_code":"0",
                              "inputTV":"",
                              "inputTVtype":"",
                              "validation":"",
                              "configs":"",
                              "restrictive_condition":"",
                              "display":"",
                              "sourceFrom":"config",
                              "sources":"",
                              "inputOptionValues":"",
                              "default":"",
                              "pos":2
                            },
                            {
                              "MIGX_id":183,
                              "field":"handle_applications",
                              "caption":"",
                              "description":"",
                              "description_is_code":"0",
                              "inputTV":"",
                              "inputTVtype":"hidden",
                              "validation":"",
                              "configs":"",
                              "restrictive_condition":"",
                              "display":"",
                              "sourceFrom":"config",
                              "sources":"",
                              "inputOptionValues":"",
                              "default":1,
                              "pos":3
                            }
                          ],
                          "pos":1
                        }
                      ],
                      "contextmenus":"update||remove",
                      "actionbuttons":"addItem",
                      "columnbuttons":"",
                      "filters":"",
                      "extended":{
                        "migx_add":"",
                        "formcaption":"",
                        "update_win_title":"",
                        "win_id":"migxproducts",
                        "maxRecords":"",
                        "addNewItemAt":"bottom",
                        "multiple_formtabs":"",
                        "actionbuttonsperrow":4,
                        "winbuttonslist":"",
                        "extrahandlers":"",
                        "filtersperrow":4,
                        "packageName":"migxproducts",
                        "classname":"ProductInfo",
                        "task":"migxproducts",
                        "getlistsort":"",
                        "getlistsortdir":"",
                        "use_custom_prefix":"0",
                        "prefix":"",
                        "grid":"",
                        "gridload_mode":1,
                        "check_resid":1,
                        "check_resid_TV":"",
                        "join_alias":"",
                        "has_jointable":"yes",
                        "getlistwhere":"",
                        "joins":"",
                        "cmpmaincaption":"",
                        "cmptabcaption":"",
                        "cmptabdescription":"",
                        "cmptabcontroller":"",
                        "winbuttons":"",
                        "onsubmitsuccess":"",
                        "submitparams":""
                      },
                      "columns":[
                        {
                          "MIGX_id":1,
                          "header":"ID",
                          "dataIndex":"id",
                          "width":"",
                          "sortable":"false",
                          "show_in_grid":1,
                          "renderer":"",
                          "clickaction":"",
                          "selectorconfig":"",
                          "renderchunktpl":"",
                          "renderoptions":""
                        },
                        {
                          "MIGX_id":2,
                          "header":"Name",
                          "dataIndex":"name",
                          "width":"",
                          "sortable":"false",
                          "show_in_grid":1,
                          "renderer":"",
                          "clickaction":"",
                          "selectorconfig":"",
                          "renderchunktpl":"",
                          "renderoptions":""
                        }
                      ]
                    }
                    



                    note this lines

                              "inputOptionValues":"@EVAL return $modx->runSnippet('migxLoopCollection',array('packageName'=>'migxproducts','classname'=>'Application','tpl'=>'@CODE:[[+application]]==[[+id]]','outputSeparator'=>'||'));",
                              "default":"@EVAL return $modx->runSnippet('getProductApplicationList');",
                              "pos":1
                    


                    and the hidden handle_applications - field, which tells the save-function to handle the applications - input-options

                    this is the snippet getProductApplicationList to get the current values into the default-value of the multiple-listbox

                    <?php
                    
                    $product = $_POST['object_id'];
                    
                    $classname = 'ProductApplication';
                    $c = $modx->newQuery($classname);
                    $c->where(array('product'=>$product)); 
                    
                    $ids = array();
                    if ($collection = $modx->getCollection($classname,$c)){
                        foreach ($collection as $object){
                            $ids[] = $object->get('application'); 
                        }
                    }
                    
                    return implode('||',$ids);
                    
                    


                    I've extented the save-function of the ProductInfo-class, so no custom-update-processor is needed

                    <?php
                    
                    class ProductInfo extends xPDOSimpleObject
                    {
                    
                        public function save($cacheFlag = null)
                        {
                    
                            $result = parent::save($cacheFlag);
                    
                            $handle_applications = $this->get('handle_applications');
                    
                            if ($handle_applications) {
                                $application_ids = explode('||', $this->get('applications'));
                                $applications = array();
                                foreach ($application_ids as $id){
                                    $applications[$id] = $id;    
                                }
                    
                                if ($existing_applications = $this->getMany('ProductsApplication')) {
                                    foreach ($existing_applications as $application_object) {
                                        $id = $application_object->get('application');
                                        if (array_key_exists($id, $applications)) {
                                            unset($applications[$id]);
                                        } else {
                                            $application_object->remove();
                                        }
                                    }
                                }
                    
                                foreach ($applications as $application) {
                                    if (!empty($application) && $application_object = $this->xpdo->newObject('ProductApplication')) {
                                        $application_object->set('product', $this->get('id'));
                                        $application_object->set('application', $application);
                                        $application_object->save();
                                    }
                                }
                            }
                    
                            return $result;
                        }
                    
                    }
                    
                    
                    
                    [ed. note: Bruno17 last edited this post 12 years, 4 months ago.]
                      -------------------------------

                      you can buy me a beer, if you like MIGX

                      http://webcmsolutions.de/migx.html

                      Thanks!
                      • 24676
                      • 60 Posts
                      This is awesome - thank you so much for taking the time to help!

                      I am currently working through this and so far so good. I think it is going to be a good solution. I do however want to combine it with an embedded grid.

                      What are the relationships I need to add to make this happen. I currently have the applications grid sitting inside my products CMP but there are no applications showing. I've tried a few things but I don't seem to be getting any closer.

                      All suggestions welcome.