We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 26503
    • 620 Posts
    I have a couple of tables that relate to each other in a couple of different ways in my model, a table for fund requests that will both refer to the Entity table for a client and an employer - so it needs 2 indexes, what is the correct way to set up the XML model schema?

    Here are the tables [drastically shortened!]:

        <object class="FundRequest" table="fund_request" extends="xPDOSimpleObject">
    	<field key="token" dbtype="varchar" precision="50" phptype="string" null="true" />
    	<field key="unixtime" dbtype="varchar" precision="50" phptype="string" null="true" />
    
    	<field ... a bunch of fields not related to the question... />
    
            <field key="payee_uid" dbtype="int" precision="8" phptype="integer" null="true" />
    	<field key="client_uid" dbtype="int" precision="8" phptype="integer" null="false" />
    
            <aggregate alias="Entities" class="Entities" local="payee_uid" foreign="id" cardinality="one" owner="foreign" />
            <aggregate alias="Entities" class="Entities" local="client_uid" foreign="id" cardinality="one" owner="foreign" />
    
    	</object>
    
    
        <object class="Entities" table="entities" extends="xPDOSimpleObject">
            <field key="token" dbtype="varchar" precision="50" phptype="string" null="true" />
            <field key="unixtime" dbtype="varchar" precision="50" phptype="string" null="true" />
    
            <field ... a bunch of fields not related to the question... />
    
            <aggregate alias="FundRequest" class="FundRequest" foreign="payee_uid" local="id" cardinality="one" owner="local" />
            <aggregate alias="FundRequest" class="FundRequest" foreign="client_uid" local="id" cardinality="one" owner="local" />
    
        </object>


    I'm thinking I should be naming my aggregate aliases in the FundRequest tables as:

            <aggregate alias="PayeeEntity" class="Entities" local="payee_uid" foreign="id" cardinality="one" owner="foreign" />
            <aggregate alias="ClientEntity" class="Entities" local="client_uid" foreign="id" cardinality="one" owner="foreign" />


    So I can refer to them as

           $object->FundRequest->PayeeEntity->get('whatever');
    

    in my code.

    A) Is this correct?

    B) How Should I label my aliases in the Entities table?

    C) I think the alias types are correct, neither record in either table should get deleted if the other is removed.
      *** Not just websites, we also create signage, banners, print, trade show displays and more! ***

      Sean Kimball CLP, CLS.
      Technical Director / Sr. Developer | BigBlock Studios
      ._______________________________________________.
      Bigblock Studios http://www.bigblockstudios.ca Web site design & development.
      27-1300 King Street East. Box 167 Oshawa, Ontario L1H8J4 Canada.
      phone/fax: 905-426-5525
      • 30585
      • 833 Posts
      How are your two tables related to one another? I don't think you want to use aggregate relationships in both objects. There should be a composite relationship somewhere.

      Let's make some assumptions:

      1. First assumption:

      A fund request can only be submitted by one entity a time. An entity can submit more than one fund request. We're here in the presence of a One-to-Many relationship with entities being the primary table.

      In this case, your schema could look like this:
      <object class="Entities" table="entities" extends="xPDOSimpleObject">
        <field key="token" dbtype="varchar" precision="50" phptype="string" null="true" />
        <field key="unixtime" dbtype="varchar" precision="50" phptype="string" null="true" />
        
        <composite alias="Request" class="FundRequests" foreign="payee_uid" local="id" cardinality="many" owner="local" />    
        
      </object>
      <object class="FundRequests" table="fund_request" extends="xPDOSimpleObject">
        <field key="token" dbtype="varchar" precision="50" phptype="string" null="true" />
        <field key="unixtime" dbtype="varchar" precision="50" phptype="string" null="true" /> 
        <field key="payee_uid" dbtype="int" precision="8" phptype="integer" null="true" />
        <field key="client_uid" dbtype="int" precision="8" phptype="integer" null="false" />
        
        <aggregate alias="Payee" class="Entities" local="payee_uid" foreign="id" cardinality="one" owner="foreign" />
        
      </object>
      

      I went with your logic, but I'm not sure why you're using two similar fields (client_uid, payee_uid) to define your relationship. Based on your schema, I have a feeling that a client can be a payee. I've therefore omitted client_uid from the relationship.

      2. Second assumption

      A fund request can be linked to many entities and an entity can submit many fund requests. This is a Many-to-Many relationship. Both tables are primary. In this case we need a join table to bridge them. Let's call it request_entities.

      Our schema could look like this:

      <object class="Entities" table="entities" extends="xPDOSimpleObject">
        <field key="token" dbtype="varchar" precision="50" phptype="string" null="true" />
        <field key="unixtime" dbtype="varchar" precision="50" phptype="string" null="true" />
        
        <composite alias="requestEntity" class="RequestEntities" foreign="payee_uid" local="id" cardinality="many" owner="local" />        
        
      </object>
      <object class="FundRequests" table="fund_request" extends="xPDOSimpleObject">
        <field key="token" dbtype="varchar" precision="50" phptype="string" null="true" />
        <field key="unixtime" dbtype="varchar" precision="50" phptype="string" null="true" /> 
        <field key="payee_uid" dbtype="int" precision="8" phptype="integer" null="true" />
        <field key="client_uid" dbtype="int" precision="8" phptype="integer" null="false" />
        
        <composite alias="requestEntity" class="RequestEntities" foreign="request" local="id" cardinality="many" owner="local" />        
        
      </object>
      
      <object class="RequestEntities" table="request_entities" extends="xPDOSimpleObject">
        <field key="request" dbtype="int" precision="8" phptype="integer" null="true" />
        <field key="payee_uid" dbtype="int" precision="8" phptype="integer" null="true" />
        
        <aggregate alias="Payee" class="Entities" local="payee_uid" foreign="id" cardinality="one" owner="foreign" />  
        <aggregate alias="Request" class="FundRequests" local="request" foreign="id" cardinality="one" owner="foreign" />
        
      </object>
      

      As noted earlier, I've omitted the client_uid field in the relationship definitions because I have a feeling it doesn't belong there. I may be wrong. It would be helpful if you could describe how a payee is different from a client and why it should be defined in the relationship.

      I hope I didn't misunderstand you.

      [ed. note: treigh last edited this post 11 years, 9 months ago.]
        A MODx Fanatic
        • 26503
        • 620 Posts
        Actually, you are almost completely right in your assumptions, looking back at the model as a whole, the client ID is actually unnecessary [and should be removed]


        FundRequests actually belong to "Contracts" a Contract may have many FundRequests, but a FundRequest can only belong to one Contract [or none - believe it or not!!]

        Client, Payees, among others, Employers, Training Centeres etc are all synonyms for an 'Entity'

        A FundRequest can only belong to one entity [it's payee] & an Entity may have many FundRequests [Entities may also have many Contracts]

        So, yes, thank you, your advice is sound and the model probably needs a little tweaking [like renaming client/payee/etc to 'owner' or 'entity' to avoid confusion since only one entity type may 'own' an object [yes, the same entity can own both the Contract and it's FundRequests]

        Some of the indexes do need to be adjusted then even though nothing ever gets deleted [ever! - for historical reporting]

        As to the alias names, yes. it does work as I expected. You can refer to an alias as:

        $modx->ObjectAlias->get('whatever');
        

        :)
          *** Not just websites, we also create signage, banners, print, trade show displays and more! ***

          Sean Kimball CLP, CLS.
          Technical Director / Sr. Developer | BigBlock Studios
          ._______________________________________________.
          Bigblock Studios http://www.bigblockstudios.ca Web site design & development.
          27-1300 King Street East. Box 167 Oshawa, Ontario L1H8J4 Canada.
          phone/fax: 905-426-5525
          • 18373 ☆ A M B ☆
          • 3,141 Posts
          Looks like you've got it figured out, but I just wanted to add one thing about aggregate/composite..

          You can have a one-to-many relation with an aggregate as well. The difference between aggregate and composite is purely what happens when the owner object is removed; if you specify a relation as composite it will also remove the related objects. If you specify it as aggregate, it wont.

          If you want to keep everything for historical reasons, aggregate is probably safer.
            Mark Hamstra • Developer spending his days working on Premium Extras and a MODX Site Dashboard with the ability to remotely upgrade MODX and extras to make the MODX world a little better.

            Tweet me @mark_hamstra, check my infrequent blog at markhamstra.com, my slightly more frequent ramblings at MODX.today or see code at Github.
            • 30585
            • 833 Posts
            Thanks for the insight Mark.
              A MODx Fanatic
              • 26503
              • 620 Posts
              Yea - I have to fiddle with the model a bit., though a bit of a side question...

              I have tables for Programs, Contracts, Requests, all have "statuses" so I also have a table for "StatusFlags" - each program/contract/request has an aggregate alias pointing to the status_flags table ... does StatusFlags really need an alias pointing back to each Program/Contract/Request table?
                *** Not just websites, we also create signage, banners, print, trade show displays and more! ***

                Sean Kimball CLP, CLS.
                Technical Director / Sr. Developer | BigBlock Studios
                ._______________________________________________.
                Bigblock Studios http://www.bigblockstudios.ca Web site design & development.
                27-1300 King Street East. Box 167 Oshawa, Ontario L1H8J4 Canada.
                phone/fax: 905-426-5525
                • 3749
                • 24,544 Posts
                Is there some reason not to just put a status field (or fields) in the other tables? Maybe I'm misunderstanding what you're doing, but it seems like every object in the statusFlag table will have two unused fields to carry around.

                To answer your question, I'm assuming that a StatusFlag object has only one Contract,program, or request (if I'm wrong, it would be 'Many' instead of 'One'). I don't think it's required to have the reverse alias unless you want to use getOne() to go the other way or use addOne():

                $statusFlag->addOne($contractObject);
                $statusFlag->getOne('Contract')


                That said, there's really no significant overhead for having the other aliases. They really just provide information to xPDO for doing the reverse lookups, which you might need someday.
                  Did I help you? Buy me a beer
                  Get my Book: MODX:The Official Guide
                  MODX info for everyone: http://bobsguides.com/modx.html
                  My MODX Extras
                  Bob's Guides is now hosted at A2 MODX Hosting
                  • 26503
                  • 620 Posts
                  The statusflag table is 2 columns, 'id" & 'status' - pretty much every object type can have a status and most of my operations on the data will have status as $criteria... so the status_id fields are indexed for speed, also the client likes to add and update status names [frequently grrr!] - nor do I ever want to have to sort through thousands of records searching for rouge statuses smiley


                  That being said, I think it might actually be beneficial to add indexes to the statusflag table, it might be easier in some situations to look up 'stuff' by status...

                  $approved = $modx->getObject('StatusFlag', array('flag' => 'APPROVED'));

                  then I have all the programs, contracts, requests etc. I'll have to fiddle with it, might be useful, but like you said - it at least can't hurt.


                      <object class="StatusFlag" table="status_flag" extends="xPDOSimpleObject">
                          
                  		<field key="created" dbtype="timestamp" phptype="timestamp" null="false" default="CURRENT_TIMESTAMP"  extra="on update current_timestamp" />
                  		<field key="modified" dbtype="timestamp" phptype="timestamp" null="false" default="0000-00-00 00:00:00" />
                  		<field key="flag" dbtype="enum" precision="'APPROVED','REJECTED','PENDING','CLOSED','DELETED','PAID','INCOMPLETE','COMPLETED'" phptype="string" null="true" />
                  		<field key="comment" dbtype="longtext" phptype="string" null="true" />
                  
                          <aggregate alias="Program" class="Program" local="id" foreign="status_id" cardinality="many" owner="local" />
                          <aggregate alias="Contract" class="Contract" local="id" foreign="status_id" cardinality="many" owner="local" />
                          <aggregate alias="FundRequest" class="FundRequest" local="id" foreign="status_id" cardinality="many" owner="local" />
                          <aggregate alias="ProgramBudget" class="ProgramBudget" local="id" foreign="status_id" cardinality="many" owner="local" />
                  
                      </object>





                  Quote from: BobRay at Dec 30, 2014, 09:59 PM
                  Is there some reason not to just put a status field (or fields) in the other tables? Maybe I'm misunderstanding what you're doing, but it seems like every object in the statusFlag table will have two unused fields to carry around.

                  To answer your question, I'm assuming that a StatusFlag object has only one Contract,program, or request (if I'm wrong, it would be 'Many' instead of 'One'). I don't think it's required to have the reverse alias unless you want to use getOne() to go the other way or use addOne():

                  $statusFlag->addOne($contractObject);
                  $statusFlag->getOne('Contract')


                  That said, there's really no significant overhead for having the other aliases. They really just provide information to xPDO for doing the reverse lookups, which you might need someday.
                    *** Not just websites, we also create signage, banners, print, trade show displays and more! ***

                    Sean Kimball CLP, CLS.
                    Technical Director / Sr. Developer | BigBlock Studios
                    ._______________________________________________.
                    Bigblock Studios http://www.bigblockstudios.ca Web site design & development.
                    27-1300 King Street East. Box 167 Oshawa, Ontario L1H8J4 Canada.
                    phone/fax: 905-426-5525
                    • 3749
                    • 24,544 Posts
                    Putting the status in a separate table lets you search for all 'things' with a status of APPROVED, but I doubt if that's a frequent occurrence. Keeping the status with the object (iow, adding a status field to each object) would allow stuff like the code below, which I think would be a lot more common. I think it would give you significantly faster searches as well. If you added createdon and approvedon columns, it would be easier to produce reports organized by time period.

                    $approvedContracts = $modx->getObject('Contract', array('status' => 'APPROVED'));

                    Just my $.02 wink


                      Did I help you? Buy me a beer
                      Get my Book: MODX:The Official Guide
                      MODX info for everyone: http://bobsguides.com/modx.html
                      My MODX Extras
                      Bob's Guides is now hosted at A2 MODX Hosting
                      • 26503
                      • 620 Posts
                      Right now things get done like:

                      $approvedContracts = $modx->getObject('Contract', array('status_id' => 3));

                      because "APPROVED" may be "PRE-APPROVED" tomorrow wink

                      I really can't think of a situation where I might need to $approved = $modx->getObject('StatusFlag', array('flag' => 'APPROVED')); while nothing technically wrong it does feel backwards

                      [maybe dashboard reporting? all approved programs, funds, contracts? $funds = count($approved->getMany('FundRequest')); ??]
                        *** Not just websites, we also create signage, banners, print, trade show displays and more! ***

                        Sean Kimball CLP, CLS.
                        Technical Director / Sr. Developer | BigBlock Studios
                        ._______________________________________________.
                        Bigblock Studios http://www.bigblockstudios.ca Web site design & development.
                        27-1300 King Street East. Box 167 Oshawa, Ontario L1H8J4 Canada.
                        phone/fax: 905-426-5525