We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 42815
    • 3 Posts
    This is my first post and first time using MODx. Loving it so far!
    First thing I had to do was extend modUser so I can load, search, and save many different additional attributes throughout the site. I followed the tutorial on http://rtfm.modx.com/display/revolution20/Extending+modUser, which proved to be a very difficult introductory article for MODx. Thankfully, this forum is a great place to find a lot of good (and sometimes misleading) information. I finally have my table generated, which is not mentioned in the article.

    For future people searching on how to generate the table after creating class and maps with parseSchema:

    $m = $modx->getManager();
    $created = $m->createObjectContainer('Doodle');
    return $created ? 'Table created.' : 'Table not created.';


    This needs to be put into your snippet at the bottom after you loaded the class with $modx->getService()

    Now for my questions:
    I have created a complex schema with multiple tables, but only the initial table is being created that links them together. My class name is profileextended, and here is a short version of the schema:

    <model package="profileextended" baseClass="xPDOObject" platform="mysql" phpdoc-package="profileextended" phpdoc-subpackage="user" defaultEngine="MyISAM" tablePrefix="commonprefix_">
        <!-- inherit the modx user and extend it -->
        <object class="profileextended" table="profileextended" extends="modUser">
            <composite alias="profile_attributes" local="id" foreign="user" cardinality="many" owner="local" />
            <composite alias="profile_settings" local="id" foreign="user" cardinality="many" owner="local" />
            <composite alias="profile_information" local="id" foreign="user" cardinality="many" owner="local" />
        </object>
     
        <!-- Physical Attributes -->
        <object class="profile_attributes" table="profile_attributes" extends="xPDOSimpleObject">
            <field key="user" dbtype="int" phptype="integer" null="false" default="0" index="index" />
    		<field key="height" dbtype="varchar" precision="10" phptype="string" null="false" default="No Answer"/>
    		<field key="eyecolor" dbtype="varchar" precision="9" phptype="string" null="false" default="No Answer"/>
    		<field key="haircolor" dbtype="varchar" precision="9" phptype="string" null="false" default="No Answer"/>
    		<index alias="PRIMARY" name="PRIMARY" primary="true" unique="true">
    	        <column key="user" collation="A" null="false" />
    	    </index>
            <aggregate alias="profileextended" local="user" foreign="id" cardinality="one" owner="foreign" />
        </object>
     
        <!-- Site Settings -->
        <object class="profile_settings" table="profile_settings_table" extends="xPDOSimpleObject">
        	<field key="user" dbtype="int" phptype="integer" null="false" default="0" index="index" />
    		<field key="privateprofile" dbtype="bool" precision="1" phptype="boolean" null="false" default="0"/>
    		<field key="privatefullname" dbtype="bool" precision="1" phptype="boolean" null="false" default="0"/>
    		<field key="image" dbtype="bool" precision="1" phptype="boolean" null="false" default="0"/>
    		<index alias="PRIMARY" name="PRIMARY" primary="true" unique="true">
    	        <column key="user" collation="A" null="false" />
    	    </index>
    		<aggregate alias="profileextended" local="user" foreign="id" cardinality="one" owner="foreign" />
        </object>
    
        <!-- Informational Text -->
        <object class="profile_information" table="profile_information" extends="xPDOSimpleObject">
        	<field key="user" dbtype="int" phptype="integer" null="false" default="0" index="index" />
            <field key="about" dbtype="text" phptype="string" null="false" default=""/>
            <field key="favorites" dbtype="text" phptype="string" null="false" default=""/>
            <index alias="PRIMARY" name="PRIMARY" primary="true" unique="true">
    	        <column key="user" collation="A" null="false" />
    	    </index>
            <aggregate alias="profileextended" local="user" foreign="id" cardinality="one" owner="foreign" />
        </object>
    </model>
    


    There are several more tables, but that would be redundant.
    1. Is a table name necessary for the class profileextended?
    2. Will I need class names for the additional tables? Without them, my mysql map does not include the fields (and even now with the classes present, only the profileextended table gets created)
    3. I am unsure about the primary keys. Does the primary table need one? The example on extending modUser did not include them, but did mentioned them.
    4. When finally retrieving the tables, the example said I should use something similar to
    public function getSettingsObj() {
                $this->userObj->getOne('profile_settings');
                return $this->userObj->Settings;
            }

    Which will be called through
    $profileextended->getSettingsObj();

    Correct? I would prefer to do it like this:
    $profileextended->getOne('profile_settings',$id);


    Thank you for your reply, I have been agonizing over this for a couple weeks now. I just figured out how to create the table this morning (another extending modUser post in this forum gave me the code above, but had me put it in my build.schema.php, instead of the snippet).

    This question has been answered by BobRay. See the first response.

    • discuss.answer
      • 3749
      • 24,544 Posts
      Congratulations on getting as far as you have. smiley

      Every xPDO object (which is what you're trying to create) is a separate class with its own table, so yes you need a tablename and a class for each object. That, and the aggregate alias will allow you to use getOne() to get the related objects.

      Every table should have a primary key. For most existing objects (like modUser) and for objects descended from xPDOSimpleObject, you'll automatically get an id field which will be auto-incremented and it's usually the primary key.

      getOne() is never called with an ID. It is a method of the object itself, not MODX, so if cardinality is one, you will always get the one related object of the object whose method you are calling, and it always returns an MODX object (which then has to be interrogated with get() or toArray() to retrieve its fields). With Resources, for example $resource->getOne('Parent') will always return a modResource object that is the parent of the $resource object (if there is one -- resources at the root of the tree have no parent).

      If you need to get an object by ID, you would use $modx->getObject('className', $id), but using getOne() and getMany() usually makes that unnecessary.

      It looks to me like you might need only one object and one table that holds all the user information, but maybe you have reasons for doing it the way you are.

      BTW, it's not a requirement, but the convention is that the alias in an aggregate alias always starts with an uppercase letter. Aliases with a cardinality of one are singular (e.g., Parent). Aliases with a cardinality of many are plural (e.g., Children).

      You might also find this useful: http://bobsguides.com/custom-db-tables.html. There's a utility there to create the schema, and the class and map files for a table that already exists. I find it easier to create the tables, then let the utility create the schema, class, and map files. I don't have to worry about typos in the schema.

      Doing it that way, you sometimes have to modify the schema to set what object it extends and to add any aggregate or composite aliases -- then use the utility to regenerate the class and map files.

      Whatever method you use, remember that you need to recreate the class and map files every time the schema changes.
        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