We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 28215
    • 4,149 Posts
    Try:

    $modx->getService('stuff', 'MyStuff', '/path/to/file/');
    


    and rename the class file to ’mystuff.class.php’.
      shaun mccormick | bigcommerce mgr of software engineering, former modx co-architect | github | splittingred.com
      • 6902
      • 126 Posts
      Aaah. Ok - that got it.
        • 6902
        • 126 Posts
        I have the class working for the database call... but it is still exhibiting the once-only behavior that started this thread.

        The best way is to make the script a class that you can instantiate once and then save as a placeholder for reuse

        Ummm... So are you proposing that I use $modx->setPlaceholder on the class instantiation? How do I keep the connection alive?
          • 28215
          • 4,149 Posts
          Quote from: debussy at Mar 16, 2010, 04:57 PM

          Ummm... So are you proposing that I use $modx->setPlaceholder on the class instantiation? How do I keep the connection alive?
          If you have a reference to the instantiated PDO connection object in the class you’re using as a Service, then using the getService call will not load a new class each time - but rather just use that same class. Think of it like a Singleton method.

          So, you can call:

          $modx->getService('stuff', 'MyStuff', '/path/to/file/');


          And then use $modx->stuff in all your snippets - and it will be the same object. This means you could do:

          <?php
          $modx->getService('stuff', 'MyStuff', '/path/to/file/');
          $modx->stuff->pdo->query('query here');
          


          etc, and use the same PDO instance (or xpdo, if you used that.)
            shaun mccormick | bigcommerce mgr of software engineering, former modx co-architect | github | splittingred.com
            • 6902
            • 126 Posts
            Done.

            I moved the getService to its own snippet that I am calling from the template... that way it loads once per page. Then each in-content snippet call just makes use of $modx->myService.

            It’s all working except the same behavior from my first post is still being exhibited: only the first call to the database returns any results. Here’s my class code:

            <?php
            
            class PhotoLab {
            
            	public function queryArchive ($serial, $SQL_ARRAY) {
            		
            		if ( isset($serial) ) {  //<--- make sure there's something to look up
            				
            			// connect to the database
            			if(empty($dbh)) {
            				try {
            					$dbh = new PDO('mysql:host='.$SQL_ARRAY['host'].';dbname='.$SQL_ARRAY['db'], $SQL_ARRAY['user'], $SQL_ARRAY['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true));
            				} catch (PDOException $e) {}
            			}
            			
            			// CREATE QUERY TO PULL IMAGE INFO
            			// selects
            			$sql = 'SELECT img.image_serial, eve.event_name ';
            			
            			// search main table
            			$sql.= 'FROM pl_images AS img ';
            			
            			 // join event table
            			$sql.= 'LEFT JOIN pl_events AS eve ON img.image_event = eve.event_id ';
            			
            			// where clauses
            			$sql.= 'WHERE img.image_serial=? ';
            			$sql.= 'AND img.image_active=1 ';
            			
            			// limit (just in case!)
            			$sql.= 'LIMIT 1 ';
            			
            			
            			// RUN QUERY
            			$stmt = $dbh->prepare($sql);
            			$stmt->bindParam(1, $serial, PDO::PARAM_STR);
            			$stmt->execute();
            			$row = $stmt->fetch(PDO::FETCH_ASSOC);
            			
            			// close database connection;
            			//$dbh = NULL;
            		
            			if ($row===false) {
            				return 'no results found for serial number: '.$serial;
            			} else {
            				return $row;
            			}
            		
            		} else {
            			
            			return 'serial number not provided';
            		
            		}
            			
            	}
            }
            
            ?>


            This is returning on the the ’no results found for serial number: ’.$serial; line, but, again, it does work for the first call to the database. I think there must be something in the way I’m forming my PDO code that is breaking it.
              • 6902
              • 126 Posts
              Ok - I guess I just needed to give my brain a break. After the weekend, I came in and was able to code it correctly. Here’s the solution--I hope it helps someone else! Enjoy!


              1) Top-of-page snippet (I just threw this in our template since almost every page on our site will use this feature). The snippet pulls in the config file which contains all the SQL connection settings in an array. Then it loads the class and runs the "connectToDB" function of that class.

              <?php
              // get path to project folder
              $pl_path = $modx->getOption('base_path').'assets/project/';
              
              // load project class
              $modx->getService('stuff', 'MyStuff', $pl_path.'classes/');
              
              // load config
              require($pl_path.'config.inc.php');
              
              // connect to the database
              $modx->stuff->connectToDB($SQL_ARRAY);
              ?>


              2) Here’s the class that gets loaded. The "connectToDB" function also prepares the statement and uses bindParam (instead of bindValue); that way one only need change the value of the bound variable and then execute on every time you want to pull an image.

              <?php
              
              class MyStuff {
              
              	//*****************************************************************
              	// INITIALIZE VARIABLES
              	//*****************************************************************
              	private $dbh;
              	private $sth;
              	private $mySerial;
              
              	
              	//*****************************************************************
              	// INITIALIZE DATABASE CONNECTION AND QUERY
              	//*****************************************************************
              	public function connectToDB ($SQL_ARRAY) {
              		
              		// CREATE QUERY
              		try {
              			$this->dbh = new PDO('mysql:host='.$SQL_ARRAY['host'].';dbname='.$SQL_ARRAY['db'], $SQL_ARRAY['user'], $SQL_ARRAY['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true ));
              		} catch (PDOException $e) { }
              		
              		// CREATE QUERY
              		$sql = 'SELECT img.image_serial, eve.event_name '; //<--- select fields
              		$sql.= 'FROM pl_images AS img '; //<--- search main table
              		$sql.= 'LEFT JOIN pl_events AS eve ON img.image_event = eve.event_id '; //<--- join events table
              		$sql.= 'WHERE img.image_serial=:serial AND img.image_active=1 '; //<--- where clauses
              		$sql.= 'LIMIT 1 '; //<--- limit (just in case!)
              		
              		// PREPARE QUERY
              		$this->sth = $this->dbh->prepare($sql);
              		$this->sth->bindParam(':serial', $this->mySerial, PDO::PARAM_STR);
              	}
              
              	
              	//*****************************************************************
              	// QUERY THE DATABASE
              	//*****************************************************************
              	
              	public function queryArchive ($serial) {
              		
              		
              		// ENSURE THAT SERIAL WAS PROVIDED
              		if ( isset($serial) ) {
              			
              			// set current search serial number
              			$this->mySerial = $serial;
              			
              			// run query
              			$this->sth->execute(); 
              			
              			// return results
              			$row = $this->sth->fetch(PDO::FETCH_ASSOC);
              			
              			// close query
              			$this->sth->closeCursor();
              			
              			// TEST RESULTS
              			if ($row===false) {
              				return 'no results found for serial number: '.$serial;
              			} else {
              				return $row;
              			}
              		
              		// IF NO SERIAL NUMBER 
              		} else {
              			return 'serial number not provided';
              		}
              	}
              }
              ?>


              3) This snippet is called anywhere on the page where you want to place an image. Optional parameters include image width, float (left or right) or stack (left or right), a caption, and, of course, the serial number of the image. The bulk of the snippet code is offloaded into a file (#4 below).

              <?php
              // load necessary modules
              $modx->runSnippet('load_mootools');
              $modx->runSnippet('load_squeezebox');
              
              $output = '';
              
              // generate paths
              $assets = $modx->getOption('base_url').'assets/';
              $pl_url = $assets.'photolab/';
              $pl_path = $modx->getOption('base_path').'assets/project/';
              
              // include image code
              // (moved to external file for easier editing)
              require($pl_path.'processors/image.inc.php');
              
              return $output;
              ?>


              4. The contents of the file that the snippet loads. Note that the config file must be loaded again to be available to this snippet.

              <?php
              
              	// include necessary functions & libraries
              	require($pl_path.'config.inc.php');
              	require_once($pl_path.'functions/filereader.func.php');
              	require_once($pl_path.'functions/photopath.func.php');
              	
              
              	//*****************************************************************
              	// QUERY THE DATABASE
              	//*****************************************************************
              	$row = $modx->stuff->queryArchive($serial);
              	
              	
              	//*****************************************************************
              	// TEST AND SET OPTIONAL PARAMETERS
              	//*****************************************************************
              	// test for width setting - default is 250
              	$myWidth = (isset($width)) ? (int)$width : 250;
              	// minimum width is 75
              	$myWidth = ($myWidth < 75) ? 75 : $myWidth;
              	// maximum width is 736
              	$myWidth = ($myWidth > 736) ? 736 : $myWidth;
              	
              	// select image type based on image size
              	if ($myWidth == 75) {
              		$type = 'thumb';
              	} elseif ($myWidth <= 300) {
              		$type = 'web';
              	} else {
              		$type = 'small';
              	} 
              	
              	// test for float setting - default is left
              	$myFloat = ( (empty($float) & empty($stack)) || $float=='left' ) ? 'float_left' : (($float=='right') ? 'float_right' : '');
              	
              	// test for stack setting - default is none
              	$myFloat = $myFloat ? $myFloat : (( $stack=='left') ? 'stack_left' : (($stack=='right') ? 'stack_right' : '') );
              	
              	// generate width string
              	$widthString = 'width: '.$myWidth.'px;';
              	
              	
              	//*****************************************************************
              	// GENERATE DETAIL PAGE
              	//*****************************************************************
              	
              	if ( is_array($row) ) { //<--- for non-empty result
              		
              		// generate image URL
              		$dispUrl = photoPath($row['image_serial'], $type, $pl_url);
              		
              		// generate link to detail popup
              		$vars = 'serial='.$serial;
              		$detailUrl = $modx->makeUrl($DETAIL_PAGE, '', $vars);
              		
              		// read in the image link template
              		$image_tpl = get_file_contents($pl_path.'templates/image.tpl.html');
              	
              		// inject content
              		$placeholders = array('[[+pli_img]]', '[[+pli_link]]', '[[+pli_title]]', '[[+pli_class]]', '[[+pli_style]]', '[[+pli_caption]]');
              		$values = array($dispUrl, $detailUrl, $row['event_name'], $myFloat, $widthString, $caption);
              		
              		$output = str_replace($placeholders, $values, $image_tpl);
              		
              		
              	} else { //<-- for empty result
              		
              		$output = '';
              				
              	}
              	
              	
              	//*****************************************************************
              	// OUTPUT DEBUG DATA
              	//*****************************************************************	
              	if ($debug) {
              		$output .= '<div style="background: #a00; color: #fff; padding: 20px;">';
              		$output .= "Serial: <strong>$serial</strong><br/>";
              		$output .= "Result: <strong>".(is_array($row)?serialize($row):$row)."</strong><br />";
              		$output .= "Float In: <strong>$float</strong><br/>";
              		$output .= "Width In: <strong>$width</strong><br/>";
              		$output .= "Caption In: <strong>$caption</strong><br/>";
              		$output .= "Type: <strong>$type</strong><br/>";
              		$output .= "URL: <strong>$dispUrl</strong><br/>";
              		$output .= "Detail: <strong>$detailUrl</strong><br/>";
              		$output .= "Float Out: <strong>$myFloat</strong><br/>";
              		$output .= "Width Out: <strong>$myWidth</strong><br/>";
              		$output .= "Width String: <strong>$widthString</strong>";
              		$output .= '</div>';
              	}
              	
              ?>
                • 28042 ☆ A M B ☆
                • 24,524 Posts
                $modx->runSnippet('load_mootools');
                $modx->runSnippet('load_squeezebox');
                

                What are these for? Can’t you just use $modx->regClientStartupScript() or regClientScript()?
                  Studying MODX in the desert - http://sottwell.com
                  Tips and Tricks from the MODX Forums and Slack Channels - http://modxcookbook.com
                  Join the Slack Community - http://modx.org
                  • 6902
                  • 126 Posts
                  Quote from: sottwell at Mar 24, 2010, 09:58 AM

                  $modx->runSnippet('load_mootools');
                  $modx->runSnippet('load_squeezebox');
                  

                  What are these for? Can’t you just use $modx->regClientStartupScript() or regClientScript()?

                  For consistency, I’ve started doing all my tool loading in snippets - which are then called from whatever item I’m building that needs it.

                  This is good for:

                  • 1) Things only get loaded once. This prevents javascripts from breaking if you end up calling them more than once on a page--say, for instance, if you happened to use two different custom snippets on a page that both require a certain tool (like mootools), but each might also get called individually on other pages.
                  • 2) There is a big simplicity advantage. These loaders can be called on one line from all the various places I need them, but they can load more than one item if necessary. Also, I don’t have to constantly keep track of what all items a tool needs or where the resources live on the server. For example, [[load_mootools]] loads both the ’core’ and ’more’ javascripts; [[load_squeezebox]] loads javascript as well as css.
                  • 3) Easy updating. Down the road, if I want to change my version of some tool (like mootools), add or remove elements that get loaded with each "tool set", etc. I only have to change it in one place and that change propagates out to all my custom work.