We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 26503
    • 620 Posts
    Having more trouble extending moduser than I remembered ....

    $modx->addPackage('extendeduser', MODX_CORE_PATH . 'components/extendeduser/model/', 'modx_'); // this works
    $res = $modx->getCollection('UserResources'); // as does this
    $data = $modx->getCollection('UserData'); // and this
    
    $user = $modx->getObject('extUser', 2); 
    $data = $user->getOne('UserData');
    print_r($data->toArray(), true); this gives a non-object error. 


    I modified the extuser.class.php, & changed the user's class_keys to 'extUser':

    <?php
    /**
     * @package extendeduser
     * @subpackage user.mysql
     */
    class extUser extends modUser {
        function __construct(xPDO & $xpdo) {
            parent::__construct($xpdo);
            $this->set('class_key','extUser');
        }
    }
    ?>



    this has to have something to do with my schema ~ right??? I can access the tables, read & write data, just not related to the user for some reason...

    <?xml version="1.0" encoding="UTF-8"?>
    
    <model package="extendeduser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1" tablePrefix="modx_">
    
    	<object class="extUser" extends="modUser">
            <composite alias="UserData" local="id" foreign="internalKey" cardinality="one" owner="local" />
            <composite alias="UserResources" local="id" foreign="internalKey" cardinality="many" owner="local" />
        </object>
    
    	<object class="UserData" table="user_data" extends="xPDOSimpleObject">
    
    		<field key="internalKey" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default="0" index="unique" />
    		<field key="firstname" dbtype="varchar" precision="100" phptype="string" null="false" />
    		<field key="lastname" dbtype="varchar" precision="100" phptype="string" null="false" />
    		<field key="institution" dbtype="varchar" precision="100" phptype="string" null="false" />
    		<field key="specialty" dbtype="varchar" precision="100" phptype="string" null="false" />
    		<field key="eula" dbtype="enum" precision="'TRUE','FALSE'" phptype="string" null="false" />
    		<field key="oncologistdatabase" dbtype="enum" precision="'TRUE','FALSE'" phptype="string" null="false" />
    		<field key="newsletters" dbtype="text" phptype="string" null="false" />
    
    		<index alias="PRIMARY" name="PRIMARY" primary="true" unique="true" type="BTREE" >
                <column key="id" length="" collation="A" null="false" />
            </index>
            <index alias="internalKey" name="internalKey" primary="false" unique="true" type="BTREE" >
                <column key="internalKey" length="" collation="A" null="false" />
            </index>
    
    		<composite  alias="extUser" local="internalKey" foreign="id" cardinality="one" owner="foreign" />
            <!--aggregate alias="extUser" local="internalKey" foreign="id" cardinality="one" owner="foreign" /-->
            <!--aggregate alias="User" class= "modUser" local="internalKey" foreign="id" cardinality="one" owner="foreign"/-->
            <!--aggregate alias="Profile" class="modUserProfile" local="internalKey" foreign="internalKey" cardinality="one" owner="foreign"/-->
    
    	</object>
    
    
    	<object class="UserResources" table="user_resources" extends="xPDOSimpleObject">
    		<field key="internalKey" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" index="index" />
    		<field key="resource" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" index="index" />
    		<field key="favorite" dbtype="enum" precision="'TRUE','FALSE'" phptype="string" null="false" />
    		<field key="saved" dbtype="enum" precision="'TRUE','FALSE'" phptype="string" null="false" />
    		<field key="frequency" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="true" />
    
    		<index alias="PRIMARY" name="PRIMARY" primary="true" unique="true" type="BTREE" >
                <column key="id" length="" collation="A" null="false" />
            </index>
            <index alias="internalKey" name="internalKey" primary="false" unique="false" type="BTREE" >
                <column key="internalKey" length="" collation="A" null="false" />
            </index>
            <index alias="resource" name="resource" primary="false" unique="false" type="BTREE" >
                <column key="resource" length="" collation="A" null="false" />
            </index>
    		<composite  alias="extUser" local="internalKey" foreign="id" cardinality="one" owner="foreign" />
    		<!--aggregate alias="extUser" local="internalKey" foreign="id" cardinality="one" owner="foreign" /-->
            <!--aggregate alias="User" class= "modUser" local="internalKey" foreign="id" cardinality="one" owner="foreign"/-->
            <!--aggregate alias="Profile" class="modUserProfile" local="internalKey" foreign="internalKey" cardinality="one" owner="foreign"/-->
    
    	</object>
    
    	
    </model>



    Am I looking right at my error?? HELP!!
      *** Not just websites, we also create signage, banners, print, trade show displays and more! ***

      Sean Kimball CLP, CLS.
      Technical Director / Sr. Developer | BigBlock Studios
      ._______________________________________________.
      Bigblock Studios http://www.bigblockstudios.ca Web site design & development.
      27-1300 King Street East. Box 167 Oshawa, Ontario L1H8J4 Canada.
      phone/fax: 905-426-5525
      • 42562
      • 1,145 Posts
        TinymceWrapper: Complete back/frontend content solution.
        Harden your MODX site by passwording your three main folders: core, manager, connectors and renaming your assets (thank me later!)
        5 ways to sniff / hack your own sites; even with renamed/hidden folders, burst them all up, to see how secure you are not.
        • 3749
        • 24,544 Posts
        The schema itself is ignored by MODX. You have to regenerate the class and map files when you change it.

        I can't tell if you're using ClassExtender, but if you are, see the upgrade note here: https://bobsguides.com/classextender-class.html.

        Using a class_key of ext_user caused some conflicts with other packages, so ClassExtender was refactored to leave the class_key as mod_user. I'd recommend doing that. You can then get the user object the regular way and get the related Resources will be available with $user->getMany('UserResources).

        If you also need other user fields, the following is off the top of my head, so it may need some massaging:

        You can also use getObjectGraph() to get the modUser, modUserProfile, and userData fields in one query.

        $c = $modx->newQuery('userData');
        $c->where(array('User.username' => 'BobRay'));
        // I you have the user ID, do this instead:
        // $c->where(array('User.userdata_id = $userId));
        $user = $modx->getObjectGraph('userData', '{"Profile":{},"User":{}}', $c);
        
        // To get multiple users:
        // $users = $modx->getCollectionGraph('userData', '{"Profile":{},"User":{}}', $c);
        
        $userResources = $user.User->getMany('UserResources');


        There may be a way to include the related resources in the original query, but I'm not sure what it would be.


        Another tool is the SetUserPlaceholders snippet, which should set placeholders for both the regular and the extra fields.
          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
          • 26503
          • 620 Posts
          I had used classextender before, found it took some fiddling with to get it to work, and things like table names etc were hard coded throughout so it was difficult to customize. but it did get this working - it was to do with the schema. Though I'm getting a weird problem I can't seem to track down!

          I created a class:

          <?php
          if (!class_exists('memberTools')) {
              class memberTools
              {
                  function __construct(modX & $modx, array $config= array ()) {
                      $this->modx= & $modx;
                      $this->extPath= $modx->getOption('core_path',null, MODX_CORE_PATH).'components/extuser/';
                      $this->modx->addPackage('extuser', $this->extPath .'model/', 'modx_');
                      $this->_config= array_merge(array (
                          'userID' => $this->modx->user->get('id'),
                      ), $config);
                      $this->userObject = $this->getUserObj($this->_config['userID']);
                      $this->userProfileObject = $this->userObject->getOne('Profile');
                      $this->userDataObject = $this->userObject->getOne('UserData');
                      $this->userResourceCollection = $this->userObject->getMany('UserResources');
                  }
                  /**
                   * add user resource
                   * @param 
                   */
                  public function addUserResource($scriptProperties){      
                      $newResource = $this->modx->newObject('UserResources');
                      $newResource->fromArray($scriptProperties);
                      $this->userObject->addMany($newResource);
                      $this->userObject->save();
                      return;
                  }
              }
          }



          the addUserRexources function is called from a snippet:

          <?php
          $output = '';
          $core = $modx->getOption('core_path').'components/extuser/model/';
          $membertools = $modx->getService('membertools', 'memberTools', $core);
          if (!$membertools instanceof memberTools){
              $modx->log(modX::LOG_LEVEL_ERROR, 'memberTools Insantiation failed');
              return;
          }else{
              $scriptProperties = array(
                          'resource' => 23, 
                          'favorite' => 1, 
                          'saved' => 1,
                          'frequency' => 999
                      ); 
          
              $membertools->addUserResource($scriptProperties);
          }
          return;




          And it works, but it will add a seemingly random number of resource objects to my custom table (I was expecting it to add one) sometimes 2, sometimes 4, other times 6 .... always divisible by 2 though.

          Have not bee able to explain that yet.



            *** Not just websites, we also create signage, banners, print, trade show displays and more! ***

            Sean Kimball CLP, CLS.
            Technical Director / Sr. Developer | BigBlock Studios
            ._______________________________________________.
            Bigblock Studios http://www.bigblockstudios.ca Web site design & development.
            27-1300 King Street East. Box 167 Oshawa, Ontario L1H8J4 Canada.
            phone/fax: 905-426-5525
            • 3749
            • 24,544 Posts
            The only thing I can think of is that addService() is adding a new service every time you call it and all instances are executing. It seems unlikely (especially since you're seeing multiples of two), but nothing else comes to mind, unless there's a tag for the snippet someplace where it will execute multiple times (like in a template or aggregated by something like getResources). When it adds multiple records, are they duplicates of each other?

            You might try using loadClass() or addPackage() instead of getService(), and deleting all files in the core/cache directory before testing. It doesn't appear that you need getService() here, though maybe I'm missing something. getService() is meant to be called once and then used in multiple locations by referencing it with the $modx object.

            https://bobsguides.com/blog.html/2013/05/25/understanding-addpackage(),-loadclass(),-and-getservice()/



              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
              • 26503
              • 620 Posts
              Quote from: BobRay at Sep 20, 2017, 09:09 PM
              The only thing I can think of is that addService() is adding a new service every time you call it and all instances are executing. It seems unlikely (especially since you're seeing multiples of two), but nothing else comes to mind, unless there's a tag for the snippet someplace where it will execute multiple times (like in a template or aggregated by something like getResources). When it adds multiple records, are they duplicates of each other?

              You might try using loadClass() or addPackage() instead of getService(), and deleting all files in the core/cache directory before testing. It doesn't appear that you need getService() here, though maybe I'm missing something. getService() is meant to be called once and then used in multiple locations by referencing it with the $modx object.

              https://bobsguides.com/blog.html/2013/05/25/understanding-addpackage(),-loadclass(),-and-getservice()/




              I checked & double checked, the snippet is called once in the resource, getSerive is used in the snippet & the extuser package is registered in the system settings - the addPackage statement was removed from the class constructor (because it is inthe system settings) then I added a couple of logging/comments to the function that is adding the UserResources object(s) - it runs once only, but inserts 2 records!

              baffled............

              
              // snippet
              $core = MODX_CORE_PATH . 'components/extuser/model/';
              $membertools = $modx->getService('membertools', 'memberTools', $core);
              if (!$membertools instanceof memberTools){
                  $modx->log(modX::LOG_LEVEL_ERROR, 'memberTools Insantiation failed');
                  return;
              }
                  $membertools->addUserResource('tools');
              return;
              
              
              
              <?php
              
              
              if (!class_exists('memberTools')) {
                  class memberTools
                  {
                      function __construct(modX & $modx, array $config= array ()) {
                          $this->modx= & $modx;
                          $this->_config= array_merge(array (
                              'userID' => $this->modx->user->get('id'),
                          ), $config);
                          $this->userObject = $this->modx->getObject('extUser', $this->_config['userID']);
                          $this->userProfileObject = $this->userObject->getOne('Profile');
                          $this->userDataObject = $this->userObject->getOne('UserData');
                          $this->userResourceCollection = $this->userObject->getMany('UserResources');
              
                      }
                      function __destruct() {
                          unset ($this->extPath, $this->userObject, $this->userID, $this->_config);
                      }
                      /**
                       * add user resource
                       * @param 
                       */
                      public function addUserResource($scriptProperties){   
                          echo '<pre>'; print_r($scriptProperties); echo '</pre>';
                          $this->modx->log(modX::LOG_LEVEL_ERROR, '[memberTools] : addUserResources function is executing.');           
                              $newResource = $this->modx->newObject('UserResources');
                              $newResource->set('resource', 23); 
                              $newResource->set('favorite', 'true');  
                              $newResource->set('saved', 'false'); 
                              $newResource->set('frequency', 777);                
                          echo '<pre>'; print_r($newResource->toArray()); echo '</pre>';
                          $this->userObject->addMany($newResource);
                          $this->userObject->save();
                          return;
                      }
                      /**
                       * testing user functions
                       * @param 
                       */
                      public function addUserData(){        
                          $data = $this->userObject->getOne('UserData');
                          $data->set('firstname', 'GROGAN');
                          $data->set('lastname', 'PILLAR OF GOD');
                          $data->set('institution', 'yes');
                          $data->set('specialty', 'stuff');
                          $data->set('eula', 0);
                          $data->set('oncologistdatabase', 0);
                          $data->set('newsletters', 0);
                          $data->set('academicinterestother', 'Education');
                          $data->set('academicinterestother', 'stuff');
                          $data->set('academicinterestspecifics', 'stuff');
                          $data->set('clinicalinterest', 'Breast');
                          $data->set('clinicalinterestother', 'stuff');
                          $data->set('clinicalinterestspecifics', 'stuff');
                          $this->userObject->save();
                          return;
                      }
                  }
              }
              


                *** Not just websites, we also create signage, banners, print, trade show displays and more! ***

                Sean Kimball CLP, CLS.
                Technical Director / Sr. Developer | BigBlock Studios
                ._______________________________________________.
                Bigblock Studios http://www.bigblockstudios.ca Web site design & development.
                27-1300 King Street East. Box 167 Oshawa, Ontario L1H8J4 Canada.
                phone/fax: 905-426-5525
                • 26503
                • 620 Posts
                I think I solved it, the schema was updated (several times & class files were regenerated...) for some reason I had a field defining the primary key - removing that and now it only inserts the single record (as expected)

                However, now, the UserData inserts a reord the first time (one to one, as expected) with no errors in the log, but if you attempt to insert the same record again. I get 2 "Duplicate entry" errors in the log. As far as I can figure, I should only be getting one - it appears that it is trying to insert the record twice. Should I be concerned?

                Updated Schema:

                <?xml version="1.0" encoding="UTF-8"?>
                
                <model package="extuser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1" tablePrefix="modx_">
                
                	<object class="extUser" extends="modUser">
                        <composite alias="UserData" class="UserData" local="id" foreign="internalKey" cardinality="one" owner="local" />
                        <composite alias="UserResources" class="UserResources" local="id" foreign="internalKey" cardinality="many" owner="local" />
                    </object>
                
                	<object class="UserData" table="user_data" extends="xPDOSimpleObject">
                
                        <field key="internalKey" dbtype="varchar" precision="10" phptype="string" null="false" index="unique" />
                        <field key="firstname" dbtype="varchar" precision="100" phptype="string" null="false" />
                        <field key="lastname" dbtype="varchar" precision="100" phptype="string" null="false" />
                        <field key="institution" dbtype="varchar" precision="100" phptype="string" null="false" />
                        <field key="specialty" dbtype="varchar" precision="100" phptype="string" null="false" />
                        <field key="academicinterest" dbtype="enum" precision="'Education','Educational Research','Basic Science Research','Phase I/II','Clinical Trials','Phase III Clinical Trials','Health Services Research','Transitional Research','Not Applicable'" phptype="string" null="false" />
                        <field key="academicinterestother" dbtype="varchar" precision="100" phptype="string" null="false" />
                        <field key="academicinterestspecifics" dbtype="text" phptype="string" null="false" />
                        <field key="clinicalinterest" dbtype="enum" precision="'Breast','Lung','GI','GU','Head and Neck','Gynecology','Sarcoma','Melanoma','Supportive Care','Lymphoma','Myeloma','Palliative Care'" phptype="string" null="false" />
                        <field key="clinicalinterestother" dbtype="varchar" precision="100" phptype="string" null="false" />
                        <field key="clinicalinterestspecifics" dbtype="text" phptype="string" null="false" />
                        <field key="eula" dbtype="enum" precision="'TRUE','FALSE'" phptype="string" null="false" />
                        <field key="oncologistdatabase" dbtype="enum" precision="'TRUE','FALSE'" phptype="string" null="false" />
                        <field key="newsletters" dbtype="text" phptype="string" null="false" />
                        
                		<index alias="PRIMARY" name="PRIMARY" primary="true" unique="true" type="BTREE" >
                            <column key="id" length="" collation="A" null="false" />
                        </index>
                
                        <index alias="internalKey" name="internalKey" primary="false" unique="true" type="BTREE" >
                            <column key="internalKey" length="" collation="A" null="false" />
                        </index>
                
                		<aggregate  alias="extUser" local="internalKey" foreign="id" cardinality="one" owner="foreign" />
                
                	</object>
                
                	<object class="UserResources" table="user_resources" extends="xPDOSimpleObject">
                
                        <field key="internalKey" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" index="index" />
                        <field key="resource" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" index="index" />
                        <field key="favorite" dbtype="enum" precision="'TRUE','FALSE'" phptype="string" null="false" />
                        <field key="saved" dbtype="enum" precision="'TRUE','FALSE'" phptype="string" null="false" />
                        <field key="frequency" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="true" />
                
                		<index alias="PRIMARY" name="PRIMARY" primary="true" unique="true" type="BTREE" >
                            <column key="id" length="" collation="A" null="false" />
                        </index>
                
                        <index alias="internalKey" name="internalKey" primary="false" unique="false" type="BTREE" >
                            <column key="internalKey" length="" collation="A" null="false" />
                        </index>
                
                        <index alias="resource" name="resource" primary="false" unique="false" type="BTREE" >
                            <column key="resource" length="" collation="A" null="false" />
                        </index>
                
                		<aggregate  alias="extUser" local="internalKey" foreign="id" cardinality="one" owner="foreign" />
                
                	</object>
                
                	
                </model>
                  *** Not just websites, we also create signage, banners, print, trade show displays and more! ***

                  Sean Kimball CLP, CLS.
                  Technical Director / Sr. Developer | BigBlock Studios
                  ._______________________________________________.
                  Bigblock Studios http://www.bigblockstudios.ca Web site design & development.
                  27-1300 King Street East. Box 167 Oshawa, Ontario L1H8J4 Canada.
                  phone/fax: 905-426-5525
                  • 3749
                  • 24,544 Posts
                  I don't think it's critical, but I would want to fix it. I'd look for the problem outside your extended classes. Nothing about the classes or schema should make the code execute twice.

                  I think the problem may be that addMany() expects an array as an argument and you're passing it a single object.

                  Try this:

                  addMany(array($newResource));
                    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