We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 3749
    • 24,544 Posts
    I'm just guessing here, but I think if you call loadClass() with the transient argument set to true before calling getService(), you'll get what you want. loadClass() won't execute again if the class already exists.

      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
      • 32699 ☆ A M B ☆
      • 427 Posts
      Assign the plugins to OnwebPageInit, and OnWebPagePrerender.

      loadClass is totally unnecessary. The service handles it.

      Makes developing Snippets and Ajax calls much faster.

        Get your copy of MODX Revolution Building the Web Your Way http://www.sanitypress.com/books/modx-revolution-building-the-web-your-way.html

        Check out my MODX || xPDO resources here: http://www.shawnwilkerson.com
        • 32699 ☆ A M B ☆
        • 427 Posts
        Quote from: pcamelo at Jun 12, 2013, 12:59 AM
        Hello, everyone!

        I tried to change my schema and declare my objects as 'extends="xPDOSimpleObject"', but after I did that, some other scripts that already worked and retrieved info from my extra tables via getObject crashed with the error:

        PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 523800 bytes) in <rootdir>/public_html/core/xpdo/om/xpdoobject.class.php on line 1668, referer: http://<mywebsite>/index.php?id=19


        Then you probably had it working.

        You need to do so like :

        $collection = $modx->getCollection('USERSCORE', array ('userId'=> $modx->user->getPrimaryKey());
        
        if ($collection)
        foreach ($collection as $object){
        
        // do something with the object here
        
            if( is_object($object){
                print_r($object->toArray());
            }
        }
        
        


        You have to remember the inheritance ancestors. You will have an object with a lot of information attached.

        Even doing something like
        print_r($collection);


        can exhaust a server with hundreds of megs of php dedicated memory.

          Get your copy of MODX Revolution Building the Web Your Way http://www.sanitypress.com/books/modx-revolution-building-the-web-your-way.html

          Check out my MODX || xPDO resources here: http://www.shawnwilkerson.com
          • 43084
          • 34 Posts
          Quote from: wshawn at Jun 14, 2013, 07:09 AM
          Assign the plugins to OnwebPageInit, and OnWebPagePrerender.

          loadClass is totally unnecessary. The service handles it.

          Makes developing Snippets and Ajax calls much faster.


          Thanks, Shawn!

          I tried to do just that, but now, every loaded page gives me the following error for all my declared classes (except for extUser which is transient):

          [2013-06-15 02:13:05] (ERROR @ /index.php) Could not get table name for class: USERSCORE
          .
          .
          .

          Here's part of my code for the plugin:

          <?php
          $modelPath = $modx->getOption('core_path',null, MODX_CORE_PATH).'components/rate/model/';
          $modx->getService('ExtUser','rate.extUser', $modelPath, $params= array ());
          $modx->getService('Score','rate.USERSCORE', $modelPath, $params= array ());
          .
          .
          .
          


          I'm guessing this is happening because all my tables have a 'rate_' prefix on them, and that's why getService can't locate them. With addPackage I just specified the prefix like so:

          $modx->addPackage('rate','/<root path>/public_html/core/components/rate/model/','rate_')


          But how do I specify the 'rate_' prefix with getService?
          Or do I have to specify it somewhere else, like in my schema?
          Or is this error caused by something else that you know?

          Thanks in advance!
            • 32699 ☆ A M B ☆
            • 427 Posts
            You may have missed it, but my Service classes are not xPDO generated and may either extend xPDO or MODX depending on whether or not I am going to be interacting with the MODX objects.

            In fact, they are usually a Parent Class which in turn loads the xPDO generated Package via the constructor.

            Apparently, you are attempting to load components of the Package instead of the Package which is intended to load those components.

            Create a new Snippet, with almost nothing in it, except to load and test the existence of a Package.

            Disable your Service Plugin first.

            One you have that working, you will have the correct format, name, and path to create a functional Service plugin.

              Get your copy of MODX Revolution Building the Web Your Way http://www.sanitypress.com/books/modx-revolution-building-the-web-your-way.html

              Check out my MODX || xPDO resources here: http://www.shawnwilkerson.com
              • 43084
              • 34 Posts
              Quote from: wshawn at Jun 14, 2013, 07:16 AM

              You have to remember the inheritance ancestors. You will have an object with a lot of information attached.

              Even doing something like
              print_r($collection);


              can exhaust a server with hundreds of megs of php dedicated memory.

              Hmm... Okay. I am using getCollection with newQuery in order to do a search of my tables. This could throw several rows as a result. I am also using getCount and sorting my results to display them in several pages so I guess that would put a lot of strain on the memory. So I'm guessing xPDOObject carries less baggage with it than xPDOSimpleObject since the queries are working fine with it without too much memory consumption.
                • 43084
                • 34 Posts
                Quote from: wshawn at Jun 15, 2013, 12:12 PM
                You may have missed it, but my Service classes are not xPDO generated and may either extend xPDO or MODX depending on whether or not I am going to be interacting with the MODX objects.

                In fact, they are usually a Parent Class which in turn loads the xPDO generated Package via the constructor.

                Apparently, you are attempting to load components of the Package instead of the Package which is intended to load those components.

                Create a new Snippet, with almost nothing in it, except to load and test the existence of a Package.

                Disable your Service Plugin first.

                One you have that working, you will have the correct format, name, and path to create a functional Service plugin.


                It's still a little bit fuzzy for me but am I right in understanding that you can load a parent class as a service which in turn can load a whole package with several classes in it?

                Sorry if I'm sounding dumb. I thought I understood how services worked but I see I'm not quite there yet, and what I thought I knew may be blocking me from understanding the full concept.

                This mini-snippet works for me and successfully loads and tests my package:

                <?php
                $modelPath = $modx->getOption('core_path',null, MODX_CORE_PATH).'components/rate/model/';
                if(!$modx->addPackage('rate',$modelPath,'rate_')) {
                    return 'Problem loading rate module.';
                }
                


                I put this as my plugin and it works fine with what I have without having to load the package at each snippet. I know I'm still not using services, but I don't understand yet how to make the jump from the code above to a single call to a service which can load my 'rate' package (which in turn loads my 'extUser' class, my 'USERSCORE' class and three other classes).
                  • 32699 ☆ A M B ☆
                  • 427 Posts
                  If you have only one schemata, then you have only one package and is defined in the model, not in the objects. In essence, the package contains the objects.

                  <?xml version="1.0" encoding="UTF-8"?>
                  <model package="ewallet" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" phpdoc-package="ewallet" phpdoc-subpackage="" version="1.1">


                  The primary difference of an xPDOObject and the xPDOSimpleObject, is the latter includes a primary key (auto increment int).

                  Have you ever implemented an xPDO derived class before? I was just curious.

                  You may want to take a look at how MODX does it, or something like the Login Package.

                  The code I provided is from an actual current project. It works as given.
                    Get your copy of MODX Revolution Building the Web Your Way http://www.sanitypress.com/books/modx-revolution-building-the-web-your-way.html

                    Check out my MODX || xPDO resources here: http://www.shawnwilkerson.com
                    • 18373 ☆ A M B ☆
                    • 3,141 Posts
                    A service class is usually not an xPDOObject and doesn't extend xPDO or modX either. It has a __construct(modX $modx) {} function that assigns a local variable $this->modx = $modx so it can access the modX class anywhere, and the constructor can also either addPackage or loadClass anything you'd like to see. It can also be used to set a config array and offer other additional methods or variables that you want.

                    Here's an actual example of a service class:
                    class moreGallery {
                        /** @var modX */
                        public $modx;
                        public $debug = false;
                        public $config = array();
                    
                        /**
                         * @param \modX $modx
                         * @param array $config
                         */
                        function __construct(modX &$modx, array $config = array()) {
                            $this->modx =& $modx;
                    
                    
                            /**
                             * Set a bunch of config options for easy access.
                             */
                            $basePath = $this->modx->getOption('moregallery.core_path', $config, $this->modx->getOption('core_path').'components/moregallery/');
                            $assetsUrl = $this->modx->getOption('moregallery.assets_url', $config, $this->modx->getOption('assets_url').'components/moregallery/');
                            $assetsPath = $this->modx->getOption('moregallery.assets_path', $config, $this->modx->getOption('assets_path').'components/moregallery/');
                            $this->config = array_merge(array(
                                'base_bath' => $basePath,
                                'core_path' => $basePath,
                                'model_path' => $basePath.'model/moregallery/',
                                'processors_path' => $basePath.'processors/',
                                'elements_path' => $basePath.'elements/',
                                'templates_path' => $basePath.'templates/',
                                'assets_path' => $assetsPath,
                                'js_url' => $assetsUrl.'js/',
                                'css_url' => $assetsUrl.'css/',
                                'assets_url' => $assetsUrl,
                                'connector_url' => $assetsUrl.'connector.php',
                            ),$config);
                    
                            // Add the package so newObject/getObject/getCollection etc can find the model 
                            $modelPath = $this->config['model_path'];
                            $this->modx->addPackage('moregallery', $modelPath);
                    
                            // Load the lexicon.. not quite necessary but can be useful.
                            $this->modx->lexicon->load('moregallery:default');
                    
                            // This actually loads the classes, so you can do stuff like mgImage::doSomething().
                            $this->modx->loadClass('mgImage', $modelPath);
                    
                            // Keep the debug close.
                            $this->debug = $this->modx->getOption('moregallery.debug', null, false);
                        }
                    }


                    Within snippets and plugins, I load the service class with the following piece of code:
                    /** @var moreGallery $moreGallery */
                    $corePath = $modx->getOption('moregallery.core_path', null, $modx->getOption('core_path').'components/moregallery/');
                    $moreGallery = $modx->getService('moregallery', 'moreGallery' , $corePath . 'model/moregallery/');
                    if (!($moreGallery instanceof moreGallery)) {
                        $modx->log(modX::LOG_LEVEL_ERROR, 'Error loading moreGallery class from ' . $corePath);
                        return 'Error loading moreGallery class.';
                    }

                    You can see it's using getService there, pointing to core/components/moregallery/model/moregallery/ - the file in there is named moregallery.class.php and is being picked up by getService.

                    In the case of an extended user object, you will need to have the package loaded (addPackage) at all times for it to work. While you could do that with a plugin OnHandleRequest I think that's very unelegant, and instead add it as a "Extension Package". You can use this system setting to register packages (ie what we did with addPackage in the service class constructor) which need to be available at all times, like an extended user or resource class. It's a JSON array, and this is an actual example (moreGallery includes a custom resource which also needs to be available on every request):
                    [{"moregallery":{"path":"/path/to/core/components/moregallery/model/"}}]


                    You can also use the modX API to add to the extension package setting in build or bootstrap scripts:
                    $modx->addExtensionPackage('moregallery', '/path/to/core/components/moregallery/model/');


                    As for xPDOObject vs xPDOSimpleObject - they are exactly the same, except for the fact that the xPDOSimpleObject already has an "id" field which is set as an auto incrementing integer. This can be convenient to use, but if you want a different (or different type) primary key, you can do that too when extending xPDOObject.

                    I have no idea what this thread is currently discussing but I noticed a lot of confusion, so I hope this provides some clarity as to what the pieces are.
                      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.
                      • 32699 ☆ A M B ☆
                      • 427 Posts
                      Quote from: markh at Jun 16, 2013, 07:12 AM
                      A service class is usually not an xPDOObject and doesn't extend xPDO or modX either. It has a __construct(modX $modx) {} function that assigns a local variable $this->modx = $modx so it can access the modX class anywhere, and the constructor can also either addPackage or loadClass anything you'd like to see. It can also be used to set a config array and offer other additional methods or variables that you want.

                      Mark,

                      Thanks for the input.

                      There are cases to where xPDO or MODX is extended, well mostly xPDO when a standalone application is being built. For some odd reason there are those who do not build on MODX sites exclusively with xPDO....

                      Hopefully, your post will help the OP to get his application running.
                        Get your copy of MODX Revolution Building the Web Your Way http://www.sanitypress.com/books/modx-revolution-building-the-web-your-way.html

                        Check out my MODX || xPDO resources here: http://www.shawnwilkerson.com