We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 28708
    • 14 Posts
    I’m trying to accomplish the exact same thing, but I can’t seem to get past object relation.

    Here’s my schema:
    <?xml version="1.0" encoding="UTF-8"?>
    <model package="webuser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" phpdoc-package="webuser" phpdoc-subpackage="model">
    	<object class="webUser" table="user_webuser_attributes" extends="xPDOSimpleObject">
    		<field key="internalKey" dbtype="int" precision="10" phptype="integer" null="false" default="0" index="unique" />
    		<field key="first_name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
    		<field key="last_name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
    		
    		<aggregate alias="User" class="modUser" local="internalKey" foreign="id" cardinality="one" owner="foreign" />
    	</object>
    </model>
    

    I have no idea if I’m handling the aggregate element correctly or not.

    And here’s the code I am attempting to test it with:
    <?php  
    /** 
     * @package webuser
     */  
    $base_path = !empty($base_path) ? $base_path : $modx->getOption('core_path').'components/webuser/';
    $modx->addPackage('webuser',$base_path.'model/'); 
    
    $user = $modx->getObject('modUser', 2);
    
    $webuser = $modx->newObject('webUser');  
    $webuser->fromArray(array(
        'first_name' => 'John',
        'last_name' => 'Doe',
    ));
    $user->addOne($webuser);  
    $user->save();  
    
    $webusers = $modx->getCollection('webUser');
    echo 'Total: '.count($webusers);
    


    It is basically a combination of the aforementioned tutorial and the addOne documentation. When I run that, I get the following error:
    (ERROR @ /index.php) No foreign key definition for parentClass: modUser using relation alias: webuser
    


    Ultimately, I would like to have these additional fields editable in the manager. Is this possible and am I even on the right track?
      • 22303 MODX Staff
      • 10,725 Posts
      strux, you are trying to use a relationship defined in/from modUser to your webUser class, which would mean you would have to modify the MODx core schema and modify the map, or more preferably, provide a custom modUser derivative class (a tutorial that shows how to do this is in development) that adds this custom relationship to your modUser derivative. And in fact, you would be better off using a derivative of modUser; it could simplify your schema/code to:
      	<object class="webUser" extends="modUser">
      		<composite alias="MyProfile" class="myWebUserProfile" local="id" foreign="internalKey" cardinality="one" owner="local" />
      	</object>
      	<object class="myWebUserProfile" table="user_webuser_attributes" extends="xPDOSimpleObject">
      		<field key="internalKey" dbtype="int" precision="10" phptype="integer" null="false" default="0" index="unique" />
      		<field key="first_name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
      		<field key="last_name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
      		
      		<aggregate alias="User" class="webUser" local="internalKey" foreign="id" cardinality="one" owner="foreign" />
      	</object>
      
      <?php  
      /** 
       * @package webuser
       */  
      $base_path = !empty($base_path) ? $base_path : $modx->getOption('core_path').'components/webuser/';
      $modx->addPackage('webuser',$base_path.'model/'); 
      
      $user = $modx->getObjectGraph('webUser', '{"MyProfile":{}}', 2);
      if (!is_object($user->MyProfile)) {
          $user->addOne('MyProfile', $modx->newObject('myWebUserProfile', array(
              'first_name' => 'John',
              'last_name' => 'Doe',
          ));
          $user->save();  
      }
      
      $webusers = $modx->getCollection('myWebUserProfile');
      


      I’ll finish the tutorial on extending modUser soon and provide a functional example we’ve been using on modxcms.com for a while now.
        • 20256
        • 49 Posts
        Do not be discouraged relationships with auto-generated numbers to a relationship?
        For cases of failure and reconstruction of databases or backup

        <field key="internalKey" dbtype="int" precision="10" phptype="integer" null="false" default="0" index="unique" />
        <aggregate alias="User" class="webUser" local="internalKey" foreign="id" cardinality="one" owner="foreign" />

        Would not it be better in a username is than unique?


        <object class="webUser" extends="modUser">
        <composite alias="MyProfile" class="myWebUserProfile" local="username" foreign="nickname" cardinality="one" owner="local" />
        </object>
        <object class="myWebUserProfile" table="user_webuser_attributes" extends="xPDOSimpleObject">
        <field key="nickname" dbtype="varchar" precision="100" phptype="string" null="false" default="0" index="index" />
        <field key="first_name" dbtype="varchar" precision="100" phptype="string" null="false" default="" />
        <field key="last_name" dbtype="varchar" precision="100" phptype="string" null="false" default="" />
        <aggregate alias="User" class="webUser" local="nickname" foreign="username" cardinality="one" owner="foreign" />
        </object>

        I ask because I am a rookie?
        This is not an assertion.
        I hope you understand
          • 22303 MODX Staff
          • 10,725 Posts
          Quote from: Mortal at Nov 15, 2009, 10:42 PM

          Do not be discouraged relationships with auto-generated numbers to a relationship?
          For cases of failure and reconstruction of databases or backup
          Not at all; most all foreign key relationships in relational databases are maintained using foreign keys to auto-generated primary keys.

          Quote from: Mortal at Nov 15, 2009, 10:42 PM

          Would not it be better in a username is than unique?
          No, because username may change, the primary key will not.
            • 28708
            • 14 Posts
            OpenGeek,

            Thanks for the reply! Extending modUser so that I can create my own relationships without modifying the base class makes complete sense. I tried out your code and and got "could not get table name for class: webUser". Taking a cue from the modx schema I added the table attribute to the webUser class and that seemed to take care of that. Now I am getting:
            Fatal error: Call to a member function addOne() on a non-object in /home/revoluti/public_html/core/components/webuser/trunk/core/components/webuser/snippet.webuser.php on line 10
            
            // Line 10
            $user->addOne('MyProfile', $modx->newObject('myWebUserProfile', array(
                    'first_name' => 'John',
                    'last_name' => 'Doe',
                )));
            

            Which I guess means my user object is not getting instantiated for some reason. I originally had
            $user = $modx->getObject('modUser', 2);
            // get user with id of 2
            

            Which is now:
            $user = $modx->getObjectGraph('webUser', '{"MyProfile":{}}', 2);
            

            Does passing in the id as the third parameter work the same way with getObjectGraph? I’m sure that isn’t the issue, but I’m at a loss.

            Here is the current state of my files:
            <?xml version="1.0" encoding="UTF-8"?>
            <model package="webuser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" phpdoc-package="webuser" phpdoc-subpackage="model">
            	<object class="webUser" table="users" extends="modUser">
            		<composite alias="MyProfile" class="myWebUserProfile" local="id" foreign="internalKey" cardinality="one" owner="local" />
            	</object>
            	<object class="myWebUserProfile" table="user_webuser_attributes" extends="xPDOSimpleObject">
            		<field key="internalKey" dbtype="int" precision="10" phptype="integer" null="false" default="0" index="unique" />
            		<field key="first_name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
            		<field key="last_name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
            		
            		<aggregate alias="User" class="webUser" local="internalKey" foreign="id" cardinality="one" owner="foreign" />
            	</object>
            </model>
            
            <?php  
            /** 
             * @package webuser 
             */  
            $base_path = !empty($base_path) ? $base_path : $modx->getOption('core_path').'components/webuser/';
            $modx->addPackage('webuser',$base_path.'model/'); 
            
            $user = $modx->getObjectGraph('webUser', '{"MyProfile":{}}', 2);	
            if (!is_object($user->MyProfile)) {
                $user->addOne('MyProfile', $modx->newObject('myWebUserProfile', array(
                    'first_name' => 'John',
                    'last_name' => 'Doe',
                )));
                $user->save();  
            }
            $webusers = $modx->getCollection('myWebUserProfile');
            echo 'Total: '.count($users);
            ?>
            
              • 28708
              • 14 Posts
              Finally got my modUser derivative class working, but I’m hoping someone can shed a little more light on the situation. I had two issues, one was that the parameters on my addOne call were reversed. Simple enough.

              More importantly, it seemed as though my webUser object or perhaps my webuser package was not being acknowledged by modx. Eventually, I tried adding my object directly to modx.mysql.schema.xml just to see what would happen and voila, everything started working. I have since removed my objects from modx.mysql.schema.xml, re-built again and things continue to work. Should I have re-built the modx schema originally after creating my package? Or maybe the changes I made to the modx schema are persisting even though I removed the objects and my package is actually still not being recognized. Did I miss some obvious step and then trigger it inadvertently by rebuilding the modx schema?

              I’m glad it’s working now, but I’d really like to know why.
                • 28215
                • 4,149 Posts
                Quote from: strux at Nov 17, 2009, 03:25 PM

                Should I have re-built the modx schema originally after creating my package?
                No.

                Or maybe the changes I made to the modx schema are persisting even though I removed the objects and my package is actually still not being recognized. Did I miss some obvious step and then trigger it inadvertently by rebuilding the modx schema?
                No, I’m pretty sure you just added your classes to the core modx maps. I can guarantee there’s a good chance that will break in future MODx updates.


                What you should have done is defined your own xml schema file and package, and used $modx->addPackage at runtime. This is explained in detail here: http://svn.modxcms.com/docs/display/revolution/Using+Custom+Database+Tables+in+your+3rd+Party+Components
                  shaun mccormick | bigcommerce mgr of software engineering, former modx co-architect | github | splittingred.com
                  • 28708
                  • 14 Posts
                  splittingred,

                  Thanks for a quick reply. Your tutorial was my starting point. You can see from these files, that they are pretty much right out of the tut. Only after having no success, did I try adding the class directly to the modx schema.
                  <?php  
                  /** 
                   * @package webuser 
                   */  
                  $base_path = !empty($base_path) ? $base_path : $modx->getOption('core_path').'components/webuser/';
                  $modx->addPackage('webuser',$base_path.'model/'); 
                  
                  $user = $modx->getObjectGraph('webUser', '{"MyProfile":{}}', 2);
                  
                  
                  if (!is_object($user->MyProfile)) {
                      $user->addOne($modx->newObject('myWebUserProfile', array(
                          'first_name' => 'John',
                          'last_name' => 'Doe',
                      )), 'MyProfile');
                      $user->save();
                  } else { echo "Here------> ".$user->MyProfile->get('first_name')."<br>"; }
                  
                  $webusers = $modx->getCollection('myWebUserProfile');
                  echo 'Total: '.count($webusers);
                  ?>
                  
                  <?xml version="1.0" encoding="UTF-8"?>
                  <model package="webuser" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" phpdoc-package="webuser" phpdoc-subpackage="model">
                  	<object class="webUser" table="users" extends="modUser">
                  		<composite alias="MyProfile" class="myWebUserProfile" key="id" local="id" foreign="internalKey" cardinality="one" owner="local" />
                  	</object>
                  	<object class="myWebUserProfile" table="user_webuser_attributes" extends="xPDOSimpleObject">
                  		<field key="internalKey" dbtype="int" precision="10" phptype="integer" null="false" default="0" index="unique" />
                  		<field key="first_name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
                  		<field key="last_name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
                  		
                  		<aggregate alias="User" class="webUser" key="id" local="internalKey" foreign="id" cardinality="one" owner="foreign" />
                  	</object>
                  </model>
                  


                  No, I’m pretty sure you just added your classes to the core modx maps. I can guarantee there’s a good chance that will break in future MODx updates.
                  No doubt, and that’s exactly why I’m trying to figure this out. I did remove the classes and rebuild, will that not remove the previously added maps?


                    • 15083
                    • 697 Posts
                    Hi guys,

                    I see a lot of people point to the tutorial above regarding building custom tables (INSERTING, SELECTING AND UPDATING ETC).
                    I think the problem here is learning curve.
                    People have 2-3+ years experience using evo and simply going:

                    $modx->insert(array(data=>value));

                    We are now faced with creating XML schemas, packages, models etc etc
                    I know why we must do the above, but I guess I am reluctant to do so as I could just use Evo and do it one tenth the time?
                    I don’t have the time to use Revo for a big project as i’m worried that I will push the project over by investigating new features.

                    Guess if I use it for my own site I can spent a bit more time.
                    The tutorial is a bit daunting, and I see myself just connecting to the DB directly now to save time (which is ultimately silly I know)

                    J

                      • 4172
                      • 5,888 Posts
                      @jusmeig:

                      creating a schema and basic classes is easy.

                      code-example:
                      <?php
                      $prefix='myprefix';
                      $packageName = 'mypackage';
                      $restrictPrefix = true;
                      
                      $manager= $modx->getManager();
                      $generator= $manager->getGenerator();
                      
                      //Use this to create a schema from an existing database
                      $xml= $generator->writeSchema($modx->getOption('core_path') . 'components/'.$packageName.'/model/schema/'.$packageName.'.mysql.schema.xml', $packageName, 'xPDOObject', $prefix, $restrictPrefix);
                      
                      //Use this to generate classes and maps from your schema
                      // NOTE: by default, only maps are overwritten; delete class files if you want to regenerate classes
                      $generator->parseSchema($modx->getOption('core_path') . 'components/'.$packageName.'/model/schema/'.$packageName.'.mysql.schema.xml', $modx->getOption('core_path') . 'components/'.$packageName.'/model/');


                      first create folder ’/core/components/mypackage/model/schema/’ and give your tables own prefixes.
                      after running this code you should have your schema and basic classes in place and you are ready to use xpdo for your tables.
                        -------------------------------

                        you can buy me a beer, if you like MIGX

                        http://webcmsolutions.de/migx.html

                        Thanks!