We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 24719
    • 194 Posts
    brilliant, thanks. I’ve got it working now. the full code for an example snippet performing an inner join is below. feel free to put in in the docs if you want.

    // Sample snippet to illustrate inner joins with xPDO.
    // Make sure you've created some records in the person, phone and person_phone tables.
    
    global $modx;
    include_once ($modx->config['base_path'].'assets/snippets/' . 'xpdo/xpdo.class.php');
    include_once ($modx->config['base_path'].'assets/snippets/' . 'xpdo/table/maketable.class.php');
    // set these as appropriate
    $xpdo= new xPDO('mysql:host=localhost;dbname=modx', "dbuser", "password");
    $xpdo->setPackage('sample');
    
    $people = array ();
    $personTbl = $xpdo->getTableName('Person');
    $phoneTbl= $xpdo->getTableName('Phone');
    $ppTbl = $xpdo->getTableName('PersonPhone');
    $personColumns= $xpdo->getSelectColumns('Person', 'p');
    $phoneColumns= $xpdo->getSelectColumns('Phone', 'ph');
    $ppColumns = $xpdo->getSelectColumns('PersonPhone', 'pp');
    
    if ($stmt= $xpdo->prepare("SELECT $personColumns,$phoneColumns,$ppColumns FROM $personTbl AS p, $phoneTbl AS ph, $ppTbl AS pp WHERE p.id=pp.person AND ph.id=pp.phone")) {
        if ($stmt->execute()) {
            foreach ($stmt->fetchAll(PDO_FETCH_ASSOC) as $row) {
                $person= $xpdo->newObject('Person');
                $person->fromArray($row, '', true);
                $phone= $xpdo->newObject('Phone');
                $phone->fromArray($row, '', true);
                $personPhone = $xpdo->newObject('PersonPhone');
                $personPhone->fromArray($row, '', true);
                $personPhone->addOne($phone);
                $person->addMany($personPhone);
                $people[]= $person;
            }
        }
    }
    
    $table = new MakeTable($xpdo);
    $tableData = false;
    
    foreach($people as $person)
    {
    	$ppSet = $person->getMany('PersonPhone');
    
    	foreach ($ppSet as $pp)
    	{
    		$number = $pp->getOne('Phone');
    		$tableData[] = array('name' => $person->get('first_name') . ' ' . $person->get('last_name'),
                                'dob' => $person->get('dob'), 'number' => $number->get('number'));
    	}
    }
    
    return $table->create($tableData);
    
      • 24719
      • 194 Posts
      a simpler way of doing this where complex sql isn’t necessary is as below. The example retrieves a particular Phone object for a particular Person - you might use this to validate that a Person is related to a Phone object before allowing them to edit the number.

      <?php 
      $person = $xpdo->getObject('Person', 1);	// get the Person object with primary key value == 1
      $pps = $person->getMany('PersonPhone');		// get all PersonPhone objects related to this Person
      $phone;					// declare this here so we can use it after the foreach loop
      foreach ($pps as $k => $v)		// loop on each PersonPhone object
      {
      	$phone = $v->getOne('Phone');		// get the Phone object related to this PersonPhone
      	// do what you want here, e.g. find a phone number with a given id passed in via a GET variable
      	if ($phone->get('id') == $_GET['id'])
      		break;
      }
      
      // do stuff with $phone...
      ?>
      
        • 23491 ☆ A M B ☆
        • 1,056 Posts
        Quote from: redman at Feb 16, 2007, 01:38 PM

        <?php 
        $person = $xpdo->getObject('Person', 1);	// get the Person object with primary key value == 1
        ?>
        


        I have a quick question: At times, I have had a PK consisting of multiple columns required to make the record Unique... Generally, there is now "row_id" record in this type of situation.

        How would you getObject for a PK like that?
          Mike Reid - www.pixelchutes.com
          MODx Ambassador / Contributor
          [Module] MultiMedia Manager / [Module] SiteSearch / [Snippet] DocPassword / [Plugin] EditArea / We support FoxyCart
          ________________________________
          Where every pixel matters.
          • 24719
          • 194 Posts
          i think this post from another thread answers your question:

          Right, basically a criteria can be any of the following:

          * a primary key value
          * an array of primary key values in the correct column order (for compound primary keys)
          * an array expression in the form array( ’[tableAlias.]fieldName[:operator]’ => value)
          * an xPDOCriteria instance (or xPDOQuery, since it is a derivative class of xPDOCriteria)


          xPDO knows what the primary key fields are and if you just pass a scalar or an array of scalars without associative keys, xPDO assumes that’s what you are searching by.
            • 22303 MODX Staff
            • 10,725 Posts
            Or, now, you can accomplish the same thing in one query to the database, using getObjectGraph():
            <?php
            $person= $xpdo->getObjectGraph('Person', '{PersonPhone:{id:{Phone:{phone:{}}}}}', 1);
            


            And also, you can now access just the phone object you want directly, by setting $xpdo->config[’hydrate_rel_obj_vars’]= true and adding some additional conditions. So, adopting your example, we can do something like this...
            <?php
            $xpdo->config['hydrate_rel_obj_vars']= true;
            $person_id= 1;
            $phone_id= 1;
            $person= $xpdo->getObjectGraph(
                'Person', 
                '{PersonPhone:{id:{Phone:{phone:{}}}}}', 
                array ('Person.id' => $person_id, 'PersonPhone.phone' => $phone_id)
            );
            $compoundKey= $person_id . '-' . $phone_id;
            $phone= & $person->PersonPhone[$compoundKey]->Phone;
            if ($phone) {
                print_r($phone->toArray());
                // ... do stuff with just the specific $phone we wanted ...
            }
            
              • 24067
              • 16 Posts
              I have been reading this post and am more confused than before.

              I understand that the topic is to create a many to many join - such as what I am trying to do.

              Tables member, member_position, position.

              $positionQuery = $modx->newQuery(’Position’);
              $positionQuery->leftJoin(’MemberPosition’, ’mp’, array(
              ’mp.position_id’ => ’position_id’,
              ’mp.member_id’ => $member_id
              )
              );

              results in the use of the string ’position_id’ in the sql. I need to list all positions and show the ones that are assigned.

              $positionQuery->select(’if(mp.member_id is null, "", "selected") selected, Position.*’);

              In addition would it be great if I knew how to set the alias for the initial table. You can set it for the from and join tables.

              Any help appreciated - also on how to populate a many to many table.

              Most valuable would be to have references to the documentation - tried to find any without luck. API does not give specifics.

                • 24067
                • 16 Posts
                Ended up using the simple and easier to manage route:


                $query = <<<SQL
                select if(mp.member_id is null, "", ’selected="selected"’) selected, p.*
                from position p
                left join member_position mp
                on mp.member_id = ’$member_id’
                and mp.position_id = p.position_id
                order by selected desc, p.name ASC
                SQL;
                $stmt = $modx->query( $query );
                if ($stmt) {
                $positions = $stmt->fetchAll(PDO::FETCH_OBJ);
                }
                foreach ($positions as $position) {
                $options .= ’<option value="’ . $position->position_id . ’" ’ . $position->selected . ’>’ .
                $position->name .
                ’</option>’;
                }