<?php
class extUser extends modUser {
function __construct(modX & $modx, array $config= array ()) {
/* Import modx as a reference */
$this->modx= & $modx;
/* Establish the environment */
$this->extPath= $modx->getOption('core_path',null, MODX_CORE_PATH).'components/extUser/';
$this->modx->addPackage('extUser', $this->extPath .'model/', 'ut_');
$this->_config= array_merge(array (
'userID' => $this->modx->user->get('id'),
), $config);
/* Define the user */
$this->userObj = $this->setUser($this->_config['userID']);
$this->userID = $this->userObj->get('id');
}
function __destruct() {
unset ($this->extPath, $this->userObj, $this->userID, $this->_config);
}
/**
* Returns object of type extUser.
*/
public function getExtUser() {
$this->userObj->getOne('ExtUser');
return $this->userObj->ExtUser;
}
/**
* Returns object utUser instance of modUser Defaults to current user.
* @param $userID
*/
public function getUserObj($userID) {
return $this->modx->getObject('modUser', $userID);
}
/**
* Establishes the user.
* @param int $userID
*/
public function setUser($userID){
return $this->getUserObj($userID);
}
public function sendNotification($type = 'general', $origin = 'system', $message = '') {
// Get the user's prefered notification method/s
// Classify the notification type
}
}<?xml version="1.0" encoding="UTF-8"?>
<model package="extendeduser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" tablePrefix="ext_" version="1.1">
<!-- inherit the modx user and extend it -->
<object class="extUser" extends="modUser">
<composite alias="ExtUser" local="id" class="UserAttributes" foreign="id" cardinality="one" owner="local" />
</object>
<!-- track all user attributes -->
<object class="UserAttributes" table="user_attributes" extends="xPDOSimpleObject">
<field key="id" dbtype="int" precision="11" phptype="integer" null="false" />
<field key="alias" dbtype="varchar" precision="64" phptype="string" null="false" />
<field key="bio" dbtype="text" phptype="string" null="false" />
<field key="followers" dbtype="longtext" phptype="string" null="false" />
<field key="following" dbtype="longtext" phptype="string" null="false" />
<field key="upvotes" dbtype="int" precision="11" phptype="integer" null="false" />
<index alias="id" name="id" primary="false" unique="true" type="BTREE">
<column key="id" length="" collation="A" null="false" />
</index>
<aggregate alias="User" class="modUser" local="id" foreign="id" cardinality="one" owner="foreign"/>
<aggregate alias="Profile" class="modUserProfile" local="id" foreign="internalKey" cardinality="one" owner="foreign"/>
</object>
</model><div class="x-form-item x-tab-item">
<label class="x-form-item-label" style="width:auto; font-weight:bold; float:none; font-size:12px">Alias</label>
<div class="x-form-item x-tab-item">
<input type="text" name="alias" value="[[+alias]]" class="x-form-text x-form-field"
onClick="Ext.getCmp('modx-panel-user').markDirty();"/>
</div>
</div>
<div class="x-form-item x-tab-item">
<label class="x-form-item-label" style="width:auto; font-weight:bold; float:none; font-size:12px">Bio</label>
<div class="x-form-item x-tab-item">
<input type="textarea" name="bio" value="[[+bio]]" class="x-form-text x-form-field"
onClick="Ext.getCmp('modx-panel-user').markDirty();"/>
</div>
</div>[[!ClassExtender?
&package=`extendeduser`
&schemaTpl=`MyExtUserSchema`
&class=`extUser`
&parentObject=`modUser`
&tablePrefix=`ext_`
&tableName=`user_attributes`
&dirPermission=`0755`
]]Generating class and map files Saving schema Old class and map files removed Schema parsed createObjectContainer() failed
<aggregate alias="User" class="modUser" local="id" foreign="id" cardinality="one" owner="foreign"/>
<aggregate alias="Profile" class="modUserProfile" local="id" foreign="internalKey" cardinality="one" owner="foreign"/>$profileObj = $extUser->getOne('Profile');
$userObj = $exsUser->getOne('User');
To answer your last question first, those lines allow you to get the relevant modUser and modUserProfile object when you have the extUser (or whatever you call it) object. Assuming that you have that object in $extUser, you can do this:
$profileObj = $extUser->getOne('Profile'); $userObj = $exsUser->getOne('User');
You can then use $obj->toArray() to create an associative array of the objects' fields, and (optionally) merge them all into one big array (be careful not to overwrite the user ID with the id field of the other objects).
Those lines also allow you to get any two or all three of the objects in one query with $modx->getCollectionGraph(), though the syntax is a little tricky until you get used to it.
Your other points show an impressive grasp of the process and I appreciate the feedback.
CE was primarily written for people who wanted a quick and easy way to get extra user fields or extra resource fields into a single table and show them on the Create/Edit User or Resource panel. I sort of threw in the opportunity to use a more complex schema, custom table names, and so on. TBH, I never really tested much beyond the default values because that wasn't the main purpose of the extra. I assumed that people who wanted more would probably not use CE, which is essentially a wizard, with the usual drawbacks the come with wizards.
If you have specific suggestions for changes that won't break the existing functionality, I'd love to hear them, though I'm swamped right now and am working on updates to at least five other extras.

function __construct(modX & $modx, array $config= array ()) {
/* Import modx as a reference */
$this->modx= & $modx;
/* Establish the environment */
$this->extPath= $modx->getOption('core_path',null, MODX_CORE_PATH).'components/extendeduser/';
$this->modx->addPackage('extendeduser', $this->extPath .'model/', 'ut_');
$this->_config= array_merge(array (
'userID' => $this->modx->user->get('id'),
), $config);
/* Define the user */
$this->userObj = $this->setUser($this->_config['userID']);
$this->userID = $this->userObj->get('id');
}function __construct(xPDO & $xpdo) {
parent::__construct($xpdo);
$this->set('class_key','extUser');
}