Hello,
I am working on a custom page type that allows a remote web resource (say, a forum) to be mounted in a SilverStripe site. To the end user, the mounted resource looks and feels like it is apart of the SS site (consistent template and navigation).
Example:
If the wrapper page is inserted at http://mysite/mount/ and is set to wrap content from http://othersite/forum/, a request for http://mysite/mount/page1/ will be forwarded to http://othersite/forum/page1/. When content is received back from othersite, the page wraps that content in the appropriate SS template.
Would you have time to critique this code?
In particular, some thoughts/questions I have:
- In WrapperPage's Children() method, how do I set the Page's URL?
- Do I need to define stageChilden() and liveChildren() in WrapperPage?
- In case you're wondering, I would like to eliminate the multiple calls to $this->loadRemotePage() by calling it once from WrapperPage's constructor, however, when I define a __construct() method on WrapperPage, the PHP script hangs. I have yet to debug this problem.
- Is there a way to eliminate the overriding of handleAction in the controller? Right now, without that override, only requests for http://mysite/mount/ will work. Requests for pages like http://mysite/mount/page1/ will return a not-found error.
FYI, I'm developing against nestedurls.
Thank you,
Ben
<?php
// Code by: Ben Gribaudo - www.bengribaudo.com
require_once 'HTTP/Request.php';
class WrapperPage extends Page {
public static $db = array(
'SourceURL' => 'Varchar(500)',
'ContentSelector' => 'Varchar(100)'
);
public static $has_one = array();
public static $allowed_children = array();
private $remotePageLoaded = false;
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->removeFieldFromTab("Root.Content.Main", "Title");
$fields->removeFieldFromTab("Root.Content.Main", "Content");
$fields->addFieldToTab('Root.Content.Main', new TextField('SourceURL', 'Source URL (No Query Strings)'));
$fields->addFieldToTab('Root.Content.Main', new TextField('ContentSelector', 'Content Selector (XPath)'));
return $fields;
}
public function onBeforeWrite() {
$this->Title = $this->MenuTitle;
return parent::onBeforeWrite();
}
public function Children() {
$this->loadRemotePage();
$children = new DataObjectSet();
foreach ($this->Children as $childTitle => $childLink) {
$page = new Page();
$page->Title = $childTitle;
// Doesn't work!
//$page->URL = $this->Link() . $childLink;
$children->push($page);
}
return $children;
}
public function Title() {
$this->loadRemotePage();
return $this->Title;
}
public function Content() {
$this->loadRemotePage();
return $this->Content;
}
private function loadRemotePage() {
if (!$this->remotePageLoaded) {
$currentURL = '/' . $this->CurrentPage()->request->getVar('url');
if (preg_match('/^' . preg_quote($this->Link(), '/') . '/i', $currentURL)) {
$subUrl = str_ireplace($this->Link(), '', $currentURL);
} else {
$subUrl = '';
}
$remotePage = new RemotePage(new WebPageLoader(new HTTP_Request()), $this->SourceURL, $this->Link(), create_function('$url', 'header("Location: $url"); exit();'), create_function('$cookie, $expires', 'setcookie($cookie["name"], $cookie["value"], $expires, $cookie["path"]);'));
$xPathDoc = $remotePage->load($subUrl, $_GET, $_POST, $_COOKIE);
$this->Title = $xPathDoc->queryFirstAsHTML('/html/head/title');
$this->Content = $xPathDoc->queryFirstAsHTML($this->getField('ContentSelector'));
// children eventually will be populated from data contained in the xPathDoc
$this->Children = array('Topic1' => 'topic1', 'Topic2' => 'topic2');
$this->remotePageLoaded = true;
}
}
}
class WrapperPage_Controller extends Page_Controller {
// $action parameter is ignored
public function handleAction($action) {
try {
return $this->renderWith($this->getViewer('index'), $this->dataRecord);
} catch (RemotePageLoadError $exception) {
return $this->httpError(500, '500 Internal Server Error');
}
}
}
?>