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.