GetExtUsers throws an error when trying to pull users

I’m using the snippet GetExtUsers to generate a list of options in a select in the MODX manager. It was working at some point, but now it geneerates a series of errors in the select:

Could not get table class for table: UserData
No foreign key definition for parentClass: UserData using relation alias: Profile
No foreign key definition for parentClass UserData using relation alias: User
Error 42000 executing query: SELECT `UserData`.`id` AS `UserData_id` FROM AS `UserData` WHERE ( `User`.`primary_group` = ? AND `User`.`active` = ? ) ORDER BY building,unit ASC, `UserData`.`id` ASC - Array ( [0] => 42000 [1] => 1064 [2] => You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS `UserData` WHERE ( `User`.`primary_group` = '2' AND `User`.`active` = '1' ) ' at line 1 ) 

Then it says “No Users Found, or no user has custom fields set”, but looking at the database it looks like the required field “primary_group” and “active” are there.

I’m on MODX 2.8.7

I guess this is from the extra ClassExtender.
What version of ClassExtender are you using?
Is it still possible to manage the custom user data in the manager, or does this also create errors?


It looks like there is a problem with the custom class UserData. Maybe the class files aren’t loaded correctly or maybe the class files got corrupted.

Okay, yeah it is ClassExtender. Version 2.3.3

I am pretty sure I can edit fields in the manager, but it’s for an apartment complex with 100+ residents.


Looks like UserData isn’t loaded correctly or maybe the class files got corrupted

How would I track that down? I inherited this bit of code from a previous developer and they didn’t leave any notes.

This is the snippet call, if that helps:

[[- Get residents that are owners (group 2) and active and sort by the building name and unit number ]]
[[GetExtUsers?
    &where=`{"User.primary_group:=":"2","User.active:=":"1"}`
    &sortby=`building,unit`
    &sortDir=`ASC`
    &extUserRowTpl=`tag-resident-tpl`
    &extUserOuterTpl=`vendor-outer-tpl`
    &extUserInnerTpl=`vendor-inner-tpl`
]]

I believe the class files should be located in core/components/classextender/model/extendeduser.


In the file core/components/classextender/model/extendeduser/mysql/userdata.map.inc.php there should be a line

'table' => 'user_data',

that tells the code what database table (ext_user_data in this case with the default prefix) corresponds to the custom PHP class UserData.

In the same file (core/components/classextender/model/extendeduser/mysql/userdata.map.inc.php) there should also be this section that defines the relationships to other tables/classes for the class UserData:

  'aggregates' => 
  array (
    'User' => 
    array (
      'class' => 'modUser',
      'local' => 'userdata_id',
      'foreign' => 'id',
      'cardinality' => 'one',
      'owner' => 'foreign',
    ),
    'Profile' => 
    array (
      'class' => 'modUserProfile',
      'local' => 'userdata_id',
      'foreign' => 'internalKey',
      'cardinality' => 'one',
      'owner' => 'foreign',
    ),
  ),

Do these lines exist?

Yes, all of that exists in the places you described.

In the snippet GetExtUsers, the code loads this file

that should register an autoload function for the custom user class.

Somehow this doesn’t seem to work correctly. (Or there maybe already exists another class with the same name?)


  • What’s the value of the system setting ce_autoload_directories?
  • Does a system setting extension_packages exist? If yes, what is the value?
  • Is there an entry in the database table modx_extension_packages from ClassExtender? What are the values?
  • extension_pacakges:
[{
  "awss3mediasource":{
    "path":"[[++core_path]]components/awss3mediasource/model/"
  }
},{
  "collections":{
    "path":"[[++core_path]]components/collections/model/"
  }
},{
  "guzzle7":{
    "serviceName":"guzzle7",
    "serviceClass":"Guzzle7",
    "path":"[[++core_path]]components/guzzle7/model/"
  }
}]
  • ce_autoload_directories: extendeduser,extendedresource

modx_extendion_packages

id namespace name path tableprefix service_class service_name created_at updated_at
3 extendeduser extendeduser [[++core_path]]components/classextender/ ext_ {date} {date}

These settings look good to me.
(It seems that it’s the entry in the modx_extension_packages database table that then actually makes the custom class available in MODX.)

Also, if the class files weren’t available, there would be an error message like “Could not load class: UserData …” instead of the error messages you posted.

I have no clue what’s going wrong here.
Maybe @bobray has an idea?

I’m baffled as well. This is the query it’s trying to run, but the second line is wrong. The FROM should be followed by a table name. There should actually be three table names in the query and there are none. I appears that it’s giving up after not finding a table name for your class.

It looks like the UserData class code is not being loaded, though the autoloader should be doing that.

Try creating a snippet called “RequireAutoloader” with this code:

require MODX_CORE_PATH . 'components\classextender\model\ce_autoload.php';
return "";

Then put the following tag above your snippet tag:

[[RequireAutoloader]]

Clear the MODX Error Log before testing.

See if that solves the problem, or gives us a different error message onscreen or in the MODX Error Log.

I don’t think my post above is going to help, as halftrainedharry has pointed out, the snippet already requires the autoloader.

Another idea is to change the code of the RequireAutoloader snippet to just include the actual UserData class file instead of the autoloader. You should also look in the actual class files in the core/components/classextender/model/ directory to see if they specify the correct namespace (extendeduser).

Something else to check. Look in the file:

core/components/classextender/model/extendeduser/mysql/userdata.map.inc.php

See if the table name matches your actual table name, including the case.

Something else to check. Look in the file:

core/components/classextender/model/extendeduser/mysql/userdata.map.inc.php

See if the table name matches your actual table name, including the case.

The table name in the .inc file is user_data and the table name is ext_user_data but that prefix is handled by class extender, right?


I’ll give the RequireAutoloader snippet a shot, when you say “specify the correct namespace” I’m not sure what you mean. Outside of small snippets of php for formatting content, I’m pretty inexperienced.

The userdata class file look like this:

<?php
class userData extends xPDOSimpleObject {}

You suspected correctly, the RequireAutoLoader snippet as you posted it did not fix it. Would the next path to try be core/components/classextender/model/extendeduser/userdata.class.php?

@bobray sorry for the ping, I realized I replied to myself and not to you. Hope you have a good new year/new years eve depending on your time zone :slight_smile:

Same to you.

What happens if you just do this:

[[!GetExtUsers]]

OK, you have nothing wrong. It’s a bug in ClassExtender.
Change the UserDataClass property in the GetExtUsers snippet from UserData to userData.

I’m still trying to figure out how to fix it without breaking existing user code. I think the GetExtResources snippet will have the same issue.

Yep, that did it! Thank you for the help during a holiday break :slight_smile:

I’m glad you got it sorted. Sorry for the trouble.

Could you do me a favor? I can’t replicate your problem.

Can you check your MyExtUserSchema chunk and see if the class name there is UserData or userData?

Also, see what the class name is in the ExtUserSchema chunk.

Here is the contents of that chunk:

<?xml version="1.0" encoding="UTF-8"?>
<model package="extendeduser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" tablePrefix="ext_" version="1.0.0">


    <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="modUserProfile" local="userdata_id" foreign="internalKey" cardinality="one" owner="foreign"/>
    </object>
</model>

Looks like it is PascalCase