I have also added these comments to the bug tracker at
http://modxcms.com/bugs/task/375
A quick recap. If you have multiple documents with the same alias getDocumentObject() always returns the first one it encounters. This might not be as intended. The code at the moment will not indicate that there are more then one eventhough looking through the code you might expect this.
In response to a question in the bug tracker I came accross another code error in getDocumentObject if called with an alias...
If the alias exists but is ’unauthorized’ two things may happen.
1. if there is another page with the same alias (that is accessible) it will return that next page object.
2. If nothing is returned (rowCount is 0) it redirects to the error (not found) page instead of what you would expect from the code being redirected to the Unauthorized Page (as set in system configuration). The query looks for
WHERE document=’$identifier’ in the documents_groups table. The document_groups table expects $identifier to be a number however so if called with an alias it will always fail. See the code snippet below (I’ve fiddled with the code so I can’t give you the correct line numbers).
<?php
//from getDocumentObject
if($rowCount<1) {
if ($this->config['unauthorized_page']) {
// check if file is not public
//TobyL: If called with an alias this will always return 0 records
$secrs = $this->dbQuery("SELECT id FROM $tbldg WHERE document = '".$identifier."' LIMIT 1;");
if($secrs) $seclimit = mysql_num_rows($secrs);
}
if ($seclimit>0) {
// match found but not publicly accessible, send the visitor to the unauthorized_page
$this->sendUnauthorizedPage();
exit; // stop here
}
else {
// no match found, send the visitor to the error_page
$this->invokeEvent('OnPageNotFound');
$this->documentIdentifier = $this->config['error_page'];
$this->documentMethod = "id";
$this->documentObject = $this->getDocumentObject(
$this->documentMethod,
$this->documentIdentifier
);
$changed = 1;
$myObject = $this->documentObject;
}
}
if ($changed) { return $myObject; }
?>
I’ve come up with a pretty simple solution I think to overcome the original problem and alleviate this second problem at the same time.
By allowing a full virtual path as the value for the $identifier parameter in getDocumentObject() (when using the alias method) the function can be called with for example "about/staff.html" and it will return the correct documentObject regardless if there is another document elsewhere with the same alias. It is fully backward compatible as far as I can see so calling it with just an alias will work equally as well.
Basically it uses the $modx->documentListing array to convert any alias into an id first.
<?php
function getDocumentObject($method,$identifier){
global $changed;
global $myObject;
//MOD by TobyL
if( !is_numeric($identifier) ){ //must be an alias
//remove first slash if any
if( substr($identifier,0,1)=='/') $identifier = substr($identifier,1);
//remove suffix if any
$identifier = ($i=strrpos($identifier,"."))?substr($identifier,0,$i):$identifier;
if(isset($this->documentListing[$identifier])){
$identifier = $this->documentListing[$identifier];
$method = 'id';
}
}
//end MOD
//...existing code
}
?>