We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 14883 ☆ A M B ☆
    • 450 Posts
    I’m working on an xpdo model for a database that uses varchar fields as its foreign keys. For example, the relationship between the "Worker" table (a list of people) and the "Country" table is based on a field called ’country_id’ in each table. Each worker has one ’country’, each country can have many workers. My schema for these two tables looks like this:
     <object class="Country" table="country" extends="xPDOObject">
        <field key="country_id" dbtype="varchar" precision="4" phptype="string" null="false" default="" index="pk" />
        <field key="cname" dbtype="varchar" precision="50" phptype="string" null="false" default="" />
         ....
         <composite alias="Workers" class="Worker" local="country_id" foreign="country_id" cardinality="many" owner="local" />
        <index alias="PRIMARY" name="PRIMARY" primary="true" unique="true">
          <column key="country_id" collation="A" null="false" />
        </index>
      </object>
      <object class="Worker" table="worker" extends="xPDOObject">
        <field key="worker_id" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" index="pk"  generated="native" />
        <field key="title" dbtype="varchar" precision="5" phptype="string" null="true" />
        <field key="name" dbtype="varchar" precision="50" phptype="string" null="true" />
        <field key="country_id" dbtype="varchar" precision="4" phptype="string" null="false" default="" />
        ...
        <aggregate alias="Country" class="Country" local="country_id" foreign="country_id" cardinality="one" owner="foreign" />
    
        <index alias="PRIMARY" name="PRIMARY" primary="true" unique="true">
          <column key="worker_id" collation="A" null="false" />
        </index>
      </object>
    


    I’m pretty sure I’ve set up the relationships properly, but let me know if I haven’t.

    The values in ’country_id’ look like: ’MEXI’, ’ITAL’, ’CANA’, etc.

    I am unable to successfully do any getCollectionGraph operations like

    $workers= $xpdo->getCollectionGraph('Worker', '{ "Country": {} }'); 
    or
      $countries = $xpdo->getCollectionGraph('Country', '{ "Workers": {} }');
    


    I get the primary table, but nothing from the secondary table. With the first example, when I try to do something like
    $output .= '<p>Country: ' . $worker->Country->get('cname') . '</p>

    I get
    Fatal error: Call to a member function get() on a non-object in...


    In the 2nd example, when I try to get at the workers for a given country with:
    foreach ($country->Workers as $w) {
          $output .= '<div>' . $w->get('fname') . ' ' . $w->get('lname') . '</div>';
        }

    I don’t get any results.

    Even stranger, when I do a related object query:
    $country = $worker->getOne('Country')
    or 
    $workers = $country->getMany('Workers')
    

    ... it does return something. count($workers) returns the correct number of workers for the given country. But when I try to access the object with
    $worker->get('fname')

    ... I get the same error (call to member function get() on a non-object).

    Even when I try to get the 2nd table information with a completely manual separate query like this:
    $workers= $xpdo->getCollection('Worker'); 
    
    foreach($workers as $wrkr) {
      
       $q = $xpdo->newQuery('Country');
       $q->where(array('country_id'=>$wrkr->get('country_id')));
       $cty = $xpdo->getObject('Country', $q);
    
    }
    



    I still am not able to access any fields in the resulting object. (I’m not even sure if it is an object, I guess).

    I have no idea what is going on here. Is this because of the varchar foreign key relationships? Should I try switching them to integers? Or is there something else going on here?

      • 21257 MODX Staff
      • 730 Posts
      I looked at this last night and nothing obvious stood out to me.. Just a thought though, if you’ve been experimenting with changes to the relationships in your schema file, have you been regenerating your map files each time?
        Mike Schell
        Lead Developer, MODX Cloud
        Email: [email protected]
        GitHub: https://github.com/netProphET/
        Twitter: @mkschell
        • 14883 ☆ A M B ☆
        • 450 Posts
        Quote from: netProphET at Jun 13, 2011, 09:08 AM

        I looked at this last night and nothing obvious stood out to me.. Just a thought though, if you’ve been experimenting with changes to the relationships in your schema file, have you been regenerating your map files each time?

        Yeah. I have deleted/rebuilt the classes & map files each time I’ve modified the schema file.

        I’m hoping I’ll have some fresh insight into this this morning. If the usual pattern holds, I’m just doing something blatantly stupid that I’ve somehow overlooked.
          • 22303 MODX Staff
          • 10,725 Posts
          Primary Keys in xPDO definitely don’t have to be numeric. modContext uses a string primary key for instance. I don’t see anything obviously wrong here, though you should have index elements for your foreign keys. But that does not explain the issue... huh
            • 18373 ☆ A M B ☆
            • 3,141 Posts
            (I’m not even sure if it is an object, I guess)

            Try checking that like this:

            if ($worker instanceof Worker) { return 'This is a worker'; }
            else { return 'This is not a worker'; }


            Something I would try is instead of extending xPDOObject, extend xPDOSimpleObject - it will add a unique id field. Then you could still use your queries like you do (you just assume the country_id var to be the unique one), but perhaps the fact there’s an auto incrementing field makes xPDO feel better..
              Mark Hamstra • Developer spending his days working on Premium Extras and a MODX Site Dashboard with the ability to remotely upgrade MODX and extras to make the MODX world a little better.

              Tweet me @mark_hamstra, check my infrequent blog at markhamstra.com, my slightly more frequent ramblings at MODX.today or see code at Github.
              • 14883 ☆ A M B ☆
              • 450 Posts
              Something *really* strange is going on here.

              getCollectionGraph is still not returning anything from the secondary table.
              $worker->getOne(’Country’) is returning something, but whether it is an object or not seems to be bizarrely affected by whether or not I try to check whether it is an object.

               
              $workers= $xpdo->getCollection('Worker'); 
              foreach($workers as $wrkr) {
                $cntry = $wrkr->getOne('Country');
                $output .= '<p>Worker Name: ' . $wrkr->get('fname'). ' ' . $wrkr->get('lname');
                $output .= ' (' . $cntry->get('cname') . ')';
                $output .= '</p>';
              }
              

              ...results in "Fatal error: Call to a member function get() on a non-object... " (referring to $cntry->get(’cname’)).
              But this:
               
              $workers= $xpdo->getCollection('Worker'); 
              foreach($workers as $wrkr) {
                $cntry = $wrkr->getOne('Country');
                $output .= '<p>Worker Name: ' . $wrkr->get('fname'). ' ' . $wrkr->get('lname');
                if (is_object($cntry)) {  
                  $output .= ' (' . $cntry->get('cname') . ')';
                }
                $output .= '</p>';
              }
              

              Returns the results I want:

              Worker Name: Joe Smith (Canada)

              So it looks as if the result of $wrkr->getOne(’Country’) isn’t an object until I test to see if it is... is this some bizarre observer effect?

              Even more confused now than before...

                • 18373 ☆ A M B ☆
                • 3,141 Posts
                Or you are getting empty arrays instead of objects, and calling ->get() on that doesn’t work - obviously.


                Checking to see if $cntry is actually an object (ie - there’s a linked country) is important.


                Do you have any workers that have a country set for which there is NO country entry in that table? You may have several workers, of which only one has a country that exists in the other table as well.


                Also please see my earlier post on how to make sure what you retrieved is the object you expected.
                  Mark Hamstra • Developer spending his days working on Premium Extras and a MODX Site Dashboard with the ability to remotely upgrade MODX and extras to make the MODX world a little better.

                  Tweet me @mark_hamstra, check my infrequent blog at markhamstra.com, my slightly more frequent ramblings at MODX.today or see code at Github.
                  • 14883 ☆ A M B ☆
                  • 450 Posts
                  if ($cntry instanceOf Country) {}
                  produces the same results as
                  if (is_object($cntry)) {}

                  If I use either of those tests to wrap my code, I can use $cntry->get(’field’).
                  If I don’t wrap, I can’t use $cntry->get(’field’) because it is a "non-object".

                    • 14883 ☆ A M B ☆
                    • 450 Posts
                    Some progress. I determined that there were actually Worker records that had no country field... so the if() tests were effectively weeding those out, and preventing my code from trying to use ->get() with non-objects...

                    So that explains that particular bit of weirdness. Now I’m trying to troubleshoot the getCollectionGraph issues...

                     $countries = $xpdo->getCollectionGraph('Country', '{ "Worker": {} }');


                    results in this warning:
                    (ERROR @ /index.php) No foreign key definition for parentClass: Country using relation alias: Worker

                    I’m going to take another look at the schema and see if I can make any sense of that.
                      • 18373 ☆ A M B ☆
                      • 3,141 Posts
                      If you look at your schema, you’ll see this:
                      <composite alias="Workers" class="Worker" local="country_id" foreign="country_id" cardinality="many" owner="local" />


                      Your class name is Worker, but the alias is Workers.

                      So you should be using Workers in your getCollectionGraph.
                        Mark Hamstra • Developer spending his days working on Premium Extras and a MODX Site Dashboard with the ability to remotely upgrade MODX and extras to make the MODX world a little better.

                        Tweet me @mark_hamstra, check my infrequent blog at markhamstra.com, my slightly more frequent ramblings at MODX.today or see code at Github.