We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 3749
    • 24,544 Posts
    I'll use modUser as an example, here, but the issue extends to any extended MODX object.

    It appears to be a limitation of extending modUser that you can only do it once. If I create an extUser class and set the class_key of all users to extUser, then ActiveDirectory is installed and it changes the class_key to modActiveDirectoryUser, all my extUser code breaks.

    This solution is implied by the docs, but it doesn't work (assume that the extUser custom fields are available with $user->getOne('Data') ). As far as I can tell, using the class key will only work if the extUsers and the modActiveDirectoryUsers are different people.

    $user = $modx->getObject('modUser', 1);
    $user->set('class_key', 'extUser');
    $user->getOne('Data');
    


    I've some solutions, but they would require changes in how people extend MODX objects.

    Solution 1:

    Have every extended modUser object extend another object that extends modUser (i.e., extUser would extend modActiveDirectoryUser or vice versa) and maintain a chain of extended object so new ones could go on the end of the chain. Imo, this is ugly and unworkable.

    Solution 2:

    Have xPDO take the class_key seriously so that the following code would just work:

    $obj->set('class_key', 'extUser');
    $obj->get('Data');
    


    I doubt if this is could be done without some major mods to xPDO, so it's probably unworkable for practical purposes.

    Solution 3:

    Leave all the class_keys as modUser and create a new object of the class you need in your code:

    $user = $modx->getObject('modUser', 1);
    $fields = $user->toArray();
    $fields['class_key'] = 'extUser';
    
    $extUser = $modx->newObject('extUser');
    $extUser->fromArray($fields, "", true, true);
    
    $data = $extUser->getOne('Data');


    This appears to work, but requires the code above anywhere you want to handle an extUser object.

    Solution 4

    This is the same as solution 3, except that the conversion code would be in the xPDOObject class:

    public function convertToClass($class) {
        $fields = $this->toArray();
        $fields['class_key'] = $class;
        $obj = $this->xpdo->newObject($class);
        $obj->fromArray($fields, "", true, true);
        return $obj; /* return &$obj; ? */
    }


    Then in the code that needs an extUser object:

    $user = $modx->getObject('modUser', 1);
    $extUser = $user->convertToClass('extUser');
    $data = $extUser->getOne('Data');


    I don't think this would break any existing code (since nobody is calling convertToClass() yet). This might be the best solution in the long run. There might be some objects that would need to disallow or override convertTo(), (e.g., $modx), though it's unlikely that anyone would ever use this method for them.


    Maybe there's some easy solution that I'm not aware of. If so I'd love to see it.

    Thoughts?















    [ed. note: BobRay last edited this post 12 years, 2 months ago.]
      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
      • 43302
      • 18 Posts
      Unfortunately I do not have a good solution for this, but I wanted to mention that I have run into the exact same problem your example mentions. An extra that I'm developing requires additional fields for users, and as such I extended modUser. Then I also needed ActiveDirectory but as that uses it's own extended modUser class, they conflicted with each other. I ended up implementing my own version of modActiveDirectory into my extended modUser class so that I had access to all of that as well. A long and tiresome process, one that I would have avoided if I had known how. It would be great to see a solution to this.
        • 22303 MODX Staff
        • 10,725 Posts
        Unfortunately, this is a limitation of the current inheritance model in the core framework—there is no easy solution to this multiple inheritance problem as is. That said, this is one of the exact problems I have been working on future solutions for, and one that has a promising future by making use of Traits in PHP 5.4+.
          • 3749
          • 24,544 Posts
          I did find an easier solution that's actually pretty simple. You just make the modUser (alias: User) object and the modUserProfile (alias: Profile) object related objects in the extended user schema. Then you can get the userData object (the object in the custom db table) directly with getCollectionGraph() and they come along for the ride.

          You never actually need an extUser object and it doesn't matter what the class_key of the user object is (modUser is fine).

          $c = $modx->newQuery('userData);
          $users = $modx->getCollectionGraph($userClass, '{"Profile":{},"User":{}}', $c);
          


          Here's an example schema:

          <?xml version="1.0" encoding="UTF-8"?>
          <model package="extendeduser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" tablePrefix="ext_" version="1.0.0">
              <!-- extend the modUser class -->
              <object class="extUser" extends="modUser">
                  <composite alias="Data" local="id" class="userData" foreign="userdata_id" cardinality="one" owner="local"/>
              </object>
              <object class="userData" table="user_data" extends="xPDOSimpleObject">
                  <field key="userdata_id" dbtype="int" precision="11" phptype="integer" null="false" attributes="unsigned"/>
                  <field key="firstName" dbtype="varchar" precision="50" phptype="string" null="true"/>
                  <field key="lastName" dbtype="varchar" precision="50" phptype="string" null="true"/>
                  <field key="title" dbtype="varchar" precision="100" phptype="string" null="true"/>
                  <field key="company" dbtype="varchar" precision="100" phptype="string" null="true"/>
                  <field key="registrationDate" dbtype="datetime" phptype="datetime"/>
          
                  <index alias="userdata_id" name="userdata_id" primary="false" unique="true" type="BTREE">
                      <column key="userdata_id" length="" collation="A" null="false"/>
                  </index>
                  <aggregate alias="User" class= "modUser" local="userdata_id" foreign="id" cardinality="one" owner="foreign"/>
                  <aggregate alias="Profile" class="modUser" local="userdata_id" foreign="internalKey" cardinality="one" owner="foreign"/>
              </object>
          </model>


          Technically, you wouldn't even need the extUser object here, but I left it in case people want to have them as a separate class of users.

          You do have to add a plugin attached to OnUserRemove to remove the related userData object when a user is deleted.
            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
            • 48546
            • 1 Posts
            [offtop] I've created site built on modx revo, it's working in production now. But it has technical flaws from point of view of modx abilities. For example there weren't object-oriented modules. So, I'm digging how to graduate and to learn major technologies of modx.[/offtop]

            How could data be add upon user registration? I've created extending class by an example given in http://rtfm.modx.com/revolution/2.x/developing-in-modx/advanced-development/extending-moduser and met few difficulties. I was unable to register user in CMP putting my classname in regform. In log file caught a message: "(ERROR @ /connectors/index.php) Could not load class: extUser from mysql.extuser.".
            Moreover - is it possible to register user by Login extension with a custom user class?

            Could you please provide full template on how to extend modUser so it could be installed and used/studied for customization. [ed. note: vchekryzhev last edited this post 12 years, 2 months ago.]
              • 3749
              • 24,544 Posts
              You might want to look at the ClassExtender extra, though I'd recommend waiting until the next version comes out (soon, hopefully), which will incorporate the idea above.

              You might also want to look at the Subscribe extra, which collects and stores some information about the user during registration. It also handles adding the user to a User Group and sending them an activation email (via the Register snippet).


                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