- Intended Audience
- Overview
- Purpose
- The Rules
- Steps to extending modUser
- 1. ) Create the schema and generate a model
- 2.) Edit the extuser.class.php
- 3.) Create (or edit) extension_packages in System Settings
- 4.) Final Step Create a class to access and utilize your extended class
- 5.) Accessing the class
- Noteworthy items
- Suggested additional considerations
- Extended modUser Classes currently Available
Intended Audience
This article attempts to ride the line of beginners desiring to learn the basics of setting up an extended modUser class and those more experienced individuals needing a foundation to begin with. For fully functional applications please refer to Currenty available extended modUser classes.
Overview
By extending the MODx Revolution authentication layer we can simply and easily build very complex and varied user subsystems rivaling that of social networking, user management systems, and other applications not yet conceptualized. This ability to extend the modUser class is just one example of the underlying power of MODx Revolution. By following the steps detailed below you will quickly be on your way to developing your own user "interfaces" or sub-systems.
Purpose
Extending modUser is for those situations when user authentication interaction needs overridden, extended, enhanced, etc. The focus is purely user authentication. Also, please understand this is a a simplified working concept. You can get much more complex.
The Rules
Extending modUser does NOT mean we are adding anything to the modx_users table in the database. It simply means we are going to be appending our own data to the end of the table by attaching our data sets via relationships and a schema. At no time should an extended application actually attempt to completely replace the modUser Class. Instead we should be using it as a platform to build upon. The only indication that the user has been extended will be found by the class_key being changed from "modUser" to the extended class name.
Your extension should be used to access your extension. If the user (object) has not been extended, do not allow your extension to interact with them -- hence: let your extension die.
MODx Revolution already handles users and probably does not need much help. While we may use your extension on *our* data, please do not begin writing "bloat" which is simply repeating code already provided in the modUser class. In other words use the Revolution resources for your extended users, but do not create code to replace modUser.
Lastly, get familiar with modUser, before you begin to code. Some methods are not one-to-one as you might assume, such as attributes, which can be assigned per context, resource, etc. Typically use the modUser suggestions to access modUser methods.
Steps to extending modUser
1. ) Create the schema and generate a model
The first thing we need to accomplish, is to create an extended user schema which extends modUser. Please note that there is no aggregate relation upwards from your "main" class which is extending modUser. An example follows:
<?xml version="1.0" encoding="UTF-8"?> <model package="extendeduser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" tablePrefix="ext_"> <!-- inherit the modx user and extend it --> <object class="extUser" table="users" extends="modUser"> <composite alias="Phones" local="id" foreign="user" cardinality="many" owner="local" /> <composite alias="Table2" local="id" foreign="user" cardinality="many" owner="local" /> </object> <!-- track all user phone numbers --> <object table="phone_numbers" extends="xPDOSimpleObject"> <field key="user" dbtype="int" phptype="integer" null="false" default="0" index="index" /> <field key="areacode" dbtype="varchar" precision="3" phptype="string" null="false" default="" /> <field key="number" dbtype="varchar" precision="7" phptype="string" null="false" default="" /> <aggregate alias="extUser" local="user" foreign="id" cardinality="one" owner="foreign" /> </object> <!-- user extension --> <object table="table2" extends="xPDOSimpleObject"> <field key="user" dbtype="int" phptype="integer" null="false" default="0" index="index" /> <field key="myspaceurl" dbtype="varchar" precision="255" phptype="string" null="false" /> <aggregate alias="extUser" local="user" foreign="id" cardinality="one" owner="foreign" /> </object> </model>
You will need to parse and create the model map associated with this schema. As this process is out of the scope of this topic, please refer to Using Custom Database Tables in your 3rd Party Components for further information.
2.) Edit the extuser.class.php
To access the extended class, we have to inform modUser that the user in question has been extended. The modx_users table in the database contains a field specifically for this purpose: class_key. The default value in this field is modUser. As users are added to your site using your extension we need to "force" the name of our "main" class in the schema, namely extUser in our example.
Edit the extuser.class.php file created when you generated the model. The specific file is the one found in the top of the model tree (you should see a mysql directory) in this same folder. Edit the file to resemble the following:
<?php /** * @package extendeduser * @subpackage user.mysql */ class extUser extends modUser { function __construct(xPDO & $xpdo) { parent :: __construct($xpdo); $this->set('class_key','extUser'); } } ?>
3.) Create (or edit) extension_packages in System Settings
Access the System settings found in the System menu of the manager, and search for: extension_packages.
If the key already exists, add inside the json array
,{"extendeduser":{"path":"[[++core_path]]components/extendeduser/model/"}}
If the key does not exists
- Create a new system setting with name of extension_packages
- Key of extension_packages
- Fieldtype: Textfield
- value
[{"extendeduser":{"path":"[[++core_path]]components/extendeduser/model/"}}]
4.) Final Step Create a class to access and utilize your extended class
<?php /** * File sample.class.php (requires MODx Revolution 2.x) * Created on Aug 18, 2010 * Project shawn_wilkerson * @package extendedUser * @version 1.0 * @category User Extension * @author W. Shawn Wilkerson * @link http://www.shawnWilkerson.com * @copyright Copyright (c) 2010, W. Shawn Wilkerson. All rights reserved. * @license GPL * */ if (!class_exists('Sampleclass')) { class Sampleclass { 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 __destruct() { unset ($this->extPath, $this->userObj, $this->userID, $this->_config); } /** * Returns object of type Phone. */ public function getPhoneObj() { $this->userObj->getOne('Phones'); return $this->userObj->Phones; } /** * 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); } } }
5.) Accessing the class
In our example we will be accessing our extended user throughout our site, therefore we load it as a service as shown in the following example:
<?php
$x = $modx->getService('extendeduser','Sampleclass',$modx->getOption('core_path',null, MODX_CORE_PATH).'components/extendeduser/',$scriptProperties);
if (!($x instanceof Extendeduser)) {
$modx->log(modX::LOG_LEVEL_ERROR,'[Extendeduser] Could not load Extendeduser class.');
$modx->event->output(true);
}
return;
Noteworthy items
- Any pre existing user, will still have modUser as the class_key and therefore will not be extended or produce user objects of type extUser unless you change it
- Double check the modx.mysql.schema.xml file to make sure you are not using classes or alias it is already using, as yours will supersede the default moduser prohibiting you access to items such as the user attributes (with alias Profile)
- The extUser will not have a table created in the database, but the attached relations will
- The extended class table(s) must be in the same database as the regular modx_users table
- Symptoms of step 3 (extension_packages path) not being correct:
- Any user with the class_key of extUser will return an error upon login: "User cannot be found...". If this is the admin, access your database directly, return the class_key to modUser, login correctly and then alter the path to a correct representation of the path.
- The snippets attached to the class will intermittently work or fail altogether
- To get counts from your data (i.e. how many phone numbers does this person have) use either (any criteria can be added):
$this->modx->getCount('extPhones', array('user' => $this->userID)); $this->modx->getCount('extPhones');
It is completely possible to have multiple extended modUser systems active at the same time. It would even be feasible to extend Jason Coward's rpx extension into a hybrid system utilizing the benefits of both systems. It is also completely possible to have multiple extended modUser applications running autonomously. This is simply done by following this process for each of your extensions, changing only the "class_key" field to reflect the extended class belonging to each respective user.
Suggested additional considerations
The model files can be edited with methods and descriptions. Take a look at much of the MODx / xPDO models and you will see this done extensively.
This process can be automated and captured upon user login. For brevity sake, it is best to refer you to splittingred's github, where he provides a real world application:
Extended modUser Classes currently Available
modActiveDirectory an application which provides interaction with a Microsoft Domain Controller
rpx extension allows people to login via Facebook and other social networking medium