We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 14951
    • 151 Posts
    EDIT: This has turned into a support topic...Not really much of a commercial inquiry anymore
    The Scope:
    I’m using OpenCart (http://www.opencart.com) for an e-commerce platform on a web site I’m creating. I’d like to include the "latest products" on my home page in ModX.
    The query is already written for OpenCart, but I’d like to get it written in such a way that ModX can understand it. I made a feeble attempt, but didn’t have much luck.
    The OpenCart database is a separate database on the same server.

    For anyone interested.. this is the function that I need converted.
    	public function getLatestProducts($limit) {
    		$product_data = $this->cache->get('product.latest.' . $this->config->get('config_language_id') . '.' . (int)$this->config->get('config_store_id') . '.' . $limit);
    
    		if (!$product_data) { 
    			$query = $this->db->query("SELECT *, pd.name AS name, p.image, m.name AS manufacturer, ss.name AS stock, (SELECT AVG(r.rating) FROM " . DB_PREFIX . "review r WHERE p.product_id = r.product_id GROUP BY r.product_id) AS rating FROM " . DB_PREFIX . "product p LEFT JOIN " . DB_PREFIX . "product_description pd ON (p.product_id = pd.product_id) LEFT JOIN " . DB_PREFIX . "product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN " . DB_PREFIX . "manufacturer m ON (p.manufacturer_id = m.manufacturer_id) LEFT JOIN " . DB_PREFIX . "stock_status ss ON (p.stock_status_id = ss.stock_status_id) WHERE p.status = '1' AND p.date_available <= NOW() AND pd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "' AND ss.language_id = '" . (int)$this->config->get('config_language_id') . "' ORDER BY p.date_added DESC LIMIT " . (int)$limit);
    		 	 
    			$product_data = $query->rows;
    
    			$this->cache->set('product.latest.' . $this->config->get('config_language_id') . '.' . (int)$this->config->get('config_store_id') . '.' . $limit, $product_data);
    		}
    		
    		return $product_data;
    	}

    I’m pretty sure that the caching stuff can be removed, and that we can change the few dynamic references to "store_id" and "language_id" to hard numbers to make things easier or just set them with snippet parameters.

    IP ownership: Freely donated back to the community

    Thank you in advance for looking!
    -Jared

    EDIT: This is for Modx Revo 2.07 by the way
      • 18913
      • 654 Posts
      FWIW, I tried to follow the tutorial at Bob’s Guides, but was unable to get it to work with an external db. I’m sure the MODx deities will howl at this, but I was able to do a simple query in Revo on an external database with this snippet :

      <?php
      $link = mysql_connect('localhost', 'mydbusername', 'mydbpassword');
      if (!$link) {
          die('Could not connect: ' . mysql_error());
      }
      $output = 'Connected successfully';
      
      $db_selected = mysql_select_db('mydbname', $link);
      if (!$db_selected) {
          die ('Can\'t use database : ' . mysql_error());
      }
      
      $query = 'SELECT * FROM exampletable';
      $result = mysql_query($query, $link);
      
      while($arecord = mysql_fetch_assoc($result)) {
          $output .= 'Field 1 : ' . $arecord['firstfield'] . '<br/>';
          $output .= 'Field 2 : ' . $arecord['secondfield'] . '<br/>';
          $output .= 'Field 5 : ' . $arecord['fifthfield'] . '<br/>';
      }
      mysql_close($link);
      mysql_free_result($result);
      return $output;
      


      Obviously, this is not Revo specific, but I hope it helps. And if anyone knows of a straightforward example of connecting to a preexisting external database, I’d be interested in the link.
      Matt
        • 14951
        • 151 Posts
        Hi Matt,

        Thanks for taking a whack at that!

        Connecting to the external database was actually surprisingly easy in Revo.
        $dsn = 'mysql:host=localhost;dbname=myDbName;port=3306;charset=utf-8';
        $xpdo = new xPDO($dsn,'myDbUserName','myDbPassword');


        I’m very slowly piecing this together in the mean time until/if someone happens to beat me to it smiley

        Thus far, I have it pulling the names of the latest products in, but each is in its own array. Here is what it looks like:
        $query = $xpdo->query("SELECT `name` FROM `opproduct_description`");
        	
        	if ($query) {
        		while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
        			print_r($row);
        	}
        	}	else { echo "YOU SUCK at Programming!"; }
        


        In case it’s helpful to you or anyone else... here is the link where I figured out the connecting part:
        http://rtfm.modx.com/display/xPDO20/Database+Connections+and+xPDO
        .

        Thanks!
        -Jared
          • 18913
          • 654 Posts
          Okay, that helped a bit. At least I was able to read my database smiley (I was trying to get the function in the tutorial to work, but I was getting tripped up on the getCollection part ...)

          Anyway, $query still be set to whatever the original line of code was? In other words, isn’t there a "->rows" selector available for xPDO? (I’m sure I didn’t word that correctly, but you get the idea.)

          BTW, I’m not gunning for the $50 - I’d just like to see a solution that works, as this is one of the thinks keeping me from moving off of Evo.
          Matt
            • 14951
            • 151 Posts
            Hi Matt,

            I’m not entirely sure I’m understanding your question correctly, but in attempt to answer you...

            As far as there being a "->rows" selector for xPDO, I really don’t know. Today is my first day even looking at xPDO, but here is what I’ve found..

            If you look at my "while loop" in the previous message, it is essentially producing "rows" containing individual arrays.

            I’m not sure if this answers your question, or merely shows off my ignorance..

            One thing that has been good to figure out (again..1st day student) is that xPDO is a wrapper for PHP’s "PDO". I’m now exploring the documentation on PDOStatement->fetch. Covering ground..but very very slowly.

            If you figure out anything cool, I’d love to hear about it as I know almost nothing at the moment!

            Thanks!
            -Jared
              • 18913
              • 654 Posts
              Using something like this
              $query = $xpdo->query("SELECT * FROM `exampletable`");
              $result = $query->fetchAll(PDO::FETCH_ASSOC);
              foreach( $result as $arecord)
              {
              $output .= $arecord['firstfield']."<br />";
              }
              

              can you pass $result in place of $query->rows in your example? In other words, would setting $product_data equal to this work? Obviously, I’m unfamiliar with opencart.
              Matt
                • 14951
                • 151 Posts
                Hey Matt,

                I appreciate the continued dialog. I’m learning a lot in the process! I’ve made it a step further..
                	$query = $xpdo->query("SELECT `name` FROM `opproduct_description` LIMIT 6");
                	
                	if ($query) {
                		$names = $query->fetchAll(PDO::FETCH_COLUMN);
                		print_r($names);
                	}	else { echo "YOU SUCK at Programming!"; }

                This returns an array containing each of my product names. (e.g...below)
                Array ( [0] => ProductName1 [1] => ProductName2 [2] => ProductName3 [3] => ProductName4 [4] => ProductName5 [5] => ProductName6 )

                I think I’m actually getting this now. Although this really isn’t taking full advantage of xPDO..it think it is going to work fine for my situation until I learn all of the ins and outs of it. Now I just need to update my query to get all of the information I want.

                Once I start grabbing multiple columns data I’m going to have to go back to "PDO::FETCH_ASSOC" which should give me what I need. Where it’s going to start getting tricky for me is figuring out the SQL syntax for the INNER/LEFT/RIGHT JOIN so that I can get the information from two different tables. I’m not very familiar with SQL syntax beyond the very basics. Oh well...Learning a lot!

                Thanks!
                -Jared
                  • 3749
                  • 24,544 Posts
                  Basic PDO, as you are using, should work fine, but I don’t think you want to be using xPDO since the xPDO object is pre-connected to the MODx database and you don’t want to mess with that.

                  If you wanted to use xPDO, you could move the data tables into the MODx DB, set up an xPDO schema, and load it (see this: http://www.bobsguides.com/custom-db-tables.html ).

                  Then you could use xPDO queries. The snippet to display a product would then look something like this (with a productTpl chunk containing placeholders for the fields).

                  This assumes that &productName is a snippet parameter and ’name’ is the name field in the DB:


                  $c = array ( /* c for criteria */
                     'name' = $productName';
                  );
                  $product = $modx->getObject('modProduct', $c);
                  
                  return $modx->getChunk('productTpl', $product->toArray() );


                  If the products have categories, another snippet would display all products in category like this:

                  $c = array {
                    'category' = $category;
                  }
                  
                  $products = $modx->getCollection('modProduct', $c);
                  
                  foreach ($products as $product) {
                  
                      $output . = $modx-getChunk('productTpl', $product->toArray());
                  }
                  
                  return $output;
                  
                  


                  The criteria can be as complicated as you like. Here’s an example from the xPDO docs:

                  $query = $xpdo->newQuery('Box');
                  $query->innerJoin('Owner','User'); 
                  // the Owner is actually a User object, defined as Owner in the relationship alias
                  $query->where(array(
                      'Owner.name:LIKE' => '%a%',
                      'Box.width:>=' => 10,
                      'Box.height:!=' => 2,
                      'Box.color:IN' => array('red','green','blue'),
                  ));
                  $query->sortby('Box.name','ASC');
                  $query->sortby('Box.height','DESC');
                  $query->limit(4);
                  $boxes = $xpdo->getCollection('Box',$query);


                  xPDO is addictive and once you get used to it, it’s hard to go back to PDO.
                    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
                    • 14951
                    • 151 Posts
                    Bob,

                    First of all.. What an amazing guide! Even an idiot like me was able to follow without a single glitch!

                    I’ve pretty much got everything working with this exception.. I’m running into issues with the innerJoin function. I need to get data from two different tables where the relation is product_id. Using standard PDO, I was able to get what I wanted.. but I’m hoping to do this all as you suggested via xPDO. My query the good ol’ fashion way looked like this:
                    $query = $xpdo->query("SELECT opproduct.image, opproduct.price, opproduct_description.name FROM opproduct, opproduct_description WHERE opproduct.product_id = opproduct_description.product_id ORDER BY opproduct.date_added DESC LIMIT 6");

                    With the help of your incredible guide and some assistance from the xPDO docs I’ve came up with the following snippet:
                    <?php
                    	$path = MODX_CORE_PATH . 'components/ocLatestProducts/';
                    	$result = $modx->addPackage('ocLatestProducts',$path . 'model/','opcart_');
                    	if (! $result) {
                    	  return 'failed to add package';
                    	}
                    	
                    	$query = $modx->newQuery('Product');
                    	$query->innerJoin('ProductDescription', 'ProductDescription');
                    	$query->where(array(
                    		'ProductDescription.product_id' => 'Product.product_id'
                    	));
                    	$query->sortby('Product.date_added', 'DESC');
                    	$query->limit(6);
                    	
                    	$products = $modx->getCollection('Product',$query); 
                    
                    	$output = '<p>Total: '. count($products) . '</p>';
                    
                    	foreach($products as $product) {
                    
                    	    $output .= '<p>Name: ' . $product->get('name');
                    	    $output .= '<p>Price: ' . $product->get('price');
                    	    $output .= '<br />Image: ' . $product->get('image') . '<br /></p>';
                    	}
                    
                    	return $output;

                    When only working with a single table (or xPDOObject) I don’t have any issues getting the data, so I believe the trouble lies within my attempt to join the two tables (or xPDOObjects) via the innerJoin.

                    I’m not very confident that I entirely understand the xPDO syntax of the innerJoin function. Why is it that I enter ’ProductDescription’ twice within the innerJoin function? Is one of the two intended to be used as an alias, or am I entirely off track?

                    Again, thank you so very much for the assistance. I probably should have just posted this as a support topic in the xPDO forum, so if a moderator wants to move this..please do. I’m sure it could potentially be useful to other "learners" out there.

                    Thanks!
                    -Jared
                      • 3749
                      • 24,544 Posts
                      TBH, I’m not sure how that’s supposed to look.

                      See if this helps: http://www.shawnwilkerson.com/xpdo/using-xpdo-across-tables/xpdo-newquery-innerjoin.html
                        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