How to correctly define index aliases in Modx/xPDO models?

455 Views Asked by At

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.

1

There are 1 best solutions below

0
On

so it needs 2 indexes

In fact you tables may not have mysql indexes (maybe only PRIMARY index to improve speed when you are working with xpdo objects) at all and it will work. But with indexes requests will work faster.

When you work on architecture of you db you should analyze what kind of data will be stored and in what way you want get the data.

Let's analize you scheme.

<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" />

This is very strange and i suppose wrong. Also i start to think that you are muddled in indexes and aggregate/composite relations (i'll later call them Relations). They are not the same.

Relations allows you to make a realtion between XPDO objects. And XPDO uses this mechanism to save and get related objects.

Indexes are usefull for db. They help to improve speed of requests and to control data (for ex. UNIQUE index means that current field (or couple of fields) should have uniqie value/combination of values)

Let's talk about Relations.

So, every xpdo object has internal property _relatedObjects. So it's very powerfull thing in XPDO. And relations allows to do this (it's rather simple example):

$u = $modx->newObject('modUser');
$p = $modx->newObject('modUserProfile');

$u->fromArray(…);
$p->fromArray(…);

$u->Profile = $p;
$u->save();

When you assign $p to ->Profile setter does all work 4 u and in the end we have profile object at _relatedObjects. XPDO uses them for saving. This is a little bit complex but in short XPDO saves relatedObjects twice to keep keys and after all save needed object (modUser in our case). In the end all fields that we use for Relations will be set correctly.

About relation fields:

  • alias — name of relation
  • class — xpdo object's class
  • local - primary key field in local object
  • foreign - secondary key field in related object
  • cardinality — type of relation
  • owner — owner of key

About naming

When you try to create name for Relations your hands are free. But anyway they should be nice to understand the relation.

How i'm doing that: The best source for name is you db table name. If i'm developing a package for modx i also use it's name for tables.

Table names:

  • modx_package_obj
  • modx_package_secondobj
  • modx_package_obj_secondobj

Now we want to get maps for modx (i don't use schemes cause they are not needed for modx).

CMPGenerator helps me to create maps. Now we have objects:

  • PackageObj (id,name)
  • PackageSecondobj (id)
  • PackageObjSecondobj (id, obj_id, sobj_id)

Cause my test objects should have relation via PackageObjSecondobj i need relations.

$xpdo_meta_map['PackageObj']= array ( … 'composites' => array ( 'ObjSecondobj' => array ( 'class' => 'PackageObjSecondobj', 'local' => 'id', 'foreign' => 'obj_id', 'owner' => 'local', 'cardinality' => 'many', ), ), ); $xpdo_meta_map['PackageSecondobj']= array ( … 'composites' => array ( 'ObjSecondobj' => array ( 'class' => 'PackageObjSecondobj', 'local' => 'id', 'foreign' => 'sobj_id', 'owner' => 'local', 'cardinality' => 'many', ), ), ); $xpdo_meta_map['PackageObjSecondobj']= array ( … 'aggregates' => array ( 'Obj' => array ( 'class' => 'PackageObj', 'local' => 'obj_id', 'foreign' => 'id', 'owner' => 'foreign', 'cardinality' => 'one', ), 'Secondobj' => array ( 'class' => 'PackageSecondobj', 'local' => 'sobj_id', 'foreign' => 'id', 'owner' => 'foreign', 'cardinality' => 'one', ), ), );

So, as you see, package name + obj name for xpdo objects, obj name for Relations. It's quite simple, easy to understand and very usefull.


Let's return to your example. You have two tables and create relation to each other twice. That's very messy and won't work predictable. Also we might have troubles while saving objects.

I don't know your task and problem, which you try to solve, but can say exactly that you are doing wrong.

You can describe your task properly and maybe i can help.

UPD

As i understand you have Payees and Clients. Payee may be a client and may be not.

In this case FundRequest->Payee and FundRequest->Client relations would be nice.

Also Payee and Client should be independent objects and they may have relations.