Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

Moderators: martimiz, Sean, biapar, Willr, Ingo, swaiba

Design Critiques Requested - Remote Content Wrapper Page


Go to End
Reply


1188 Views

Avatar
Ben Gribaudo

Community Member, 181 Posts

20 May 2009 at 4:15am

Edited: 20/05/2009 4:17am

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');
		}
	}
}
?>