예제 #1
0
 public function getFormSettings()
 {
     $pages = PageModel::Find(['baseurl LIKE /blog/view/%'], null, 'title');
     $opts = array('' => 'All Blogs');
     foreach ($pages as $page) {
         $id = substr($page->get('baseurl'), 11);
         $opts[$id] = $page->get('title');
     }
     $settings = [['type' => 'text', 'name' => 'title', 'title' => 'Displayed Title', 'description' => 'Displayed title on the page where this widget is added to.'], ['type' => 'select', 'name' => 'blog', 'title' => 'Blog', 'options' => $opts, 'description' => 'Choose a specific blog if you wish to retrieve posts from a specific blog.'], ['type' => 'select', 'name' => 'count', 'title' => 'Number of results', 'options' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)], ['type' => 'select', 'name' => 'sort', 'title' => 'Sort By', 'options' => array('newest' => 'Newest', 'popular' => 'Most Popular', 'random' => 'Random')]];
     return $settings;
 }
예제 #2
0
 /**
  * Widget to quickly create a new Content page as a draft.
  */
 public function quickdraft()
 {
     $view = $this->getView();
     if (!\Core\user()->checkAccess('p:/content/manage_all')) {
         // Users who do not have access to manage page content do not get this.
         return '';
     }
     $form = new Form();
     $form->set('orientation', 'vertical');
     $form->set('callsmethod', 'ContentAdminWidget::QuickDraftSave');
     $form->addElement('text', ['name' => 'title', 'placeholder' => 'Page or Post Title']);
     $form->addElement('textarea', ['name' => 'content', 'placeholder' => "What's up?", 'cols' => 50]);
     $form->addElement('submit', ['value' => 'Save Draft']);
     // Load in all the pages on the site that are currently set as draft too, why not? ;)
     $drafts = PageModel::Find(['published_status = draft'], 10, 'updated DESC');
     $view->assign('form', $form);
     $view->assign('drafts', $drafts);
 }
예제 #3
0
	public function testBug(){
		$selectablepage = PageModel::Find(['selectable' => 1], null);
		$notselectablepage = PageModel::Find(['selectable' => 0], null);

		// Both of these should return an array!
		$this->assertNotEmpty($selectablepage);
		$this->assertNotEmpty($notselectablepage);

		// And this needs to be an array too.
		$pagearray = PageModel::GetPagesAsOptions();
		$this->assertNotEmpty($pagearray);

		// Run through each selectable page and make sure that it displays in the list.
		foreach($selectablepage as $page){
			$this->assertInstanceOf('PageModel', $page);
			$this->assertArrayHasKey($page->get('baseurl'), $pagearray);
		}

		foreach($notselectablepage as $page){
			$this->assertInstanceOf('PageModel', $page);
			$this->assertArrayNotHasKey($page->get('baseurl'), $pagearray);
		}
	}
예제 #4
0
	/**
	 * Display the admin dashboard.
	 *
	 * This page is primarily made up of widgets added by other systems.
	 *
	 * @return int
	 */
	public function index() {

		$view     = $this->getView();
		$pages    = PageModel::Find(array('admin' => '1'));
		$viewable = array();

		foreach ($pages as $p) {
			if (!\Core\user()->checkAccess($p->get('access'))) continue;

			$viewable[] = $p;
		}

		// If there are no viewable pages... don't display any admin dashboard.
		if(!sizeof($viewable)){
			return View::ERROR_ACCESSDENIED;
		}

		$view->title = 't:STRING_ADMIN';
		$view->assign('links', $viewable);

		// Dispatch the hook that other systems can hook into and perform checks or operations on the admin dashboard page.
		HookHandler::DispatchHook('/core/admin/view');
	}
	/**
	 * See the details of a given search criteria, be it IP address, session, or user.
	 */
	public function details(){
		$view = $this->getView();
		$request = $this->getPageRequest();
		
		$listing = new Core\ListingTable\Table();
		$listing->setName('useractivity-details');
		$listing->setLimit(100);

		$listing->addFilter(
			'text',
			['name' => 'user_id', 'title' => 'User ID', 'link' => FilterForm::LINK_TYPE_STANDARD]
		);

		$listing->addFilter(
			'text',
			['name' => 'ip_addr', 'title' => 'IP Address', 'link' => FilterForm::LINK_TYPE_STANDARD]
		);

		$listing->addFilter(
			'text',
			['name' => 'session_id', 'title' => 'Session ID', 'link' => FilterForm::LINK_TYPE_STANDARD]
		);

		$pages = PageModel::Find(null, null, 'baseurl');
		$allPages = ['' => '-- ' . t('STRING_ALL_PAGES') . ' --'];
		foreach($pages as $p){
			/** @var PageModel $p */
			$allPages[$p->get('baseurl')] = $p->get('baseurl');
		}
		$listing->addFilter(
			'select',
			[
				'name' => 'baseurl',
			    'title' => 'Page',
			    'options' => $allPages,
			    'link' => FilterForm::LINK_TYPE_STANDARD,
			]
		);
		
		$listing->addColumn('Time', 'datetime');
		$listing->addColumn('User & Browser');
		$listing->addColumn('Type', 'type');
		$listing->addColumn('URL & Referrer', 'request');
		$listing->addColumn('Referrer', 'referrer', false);
		$listing->addColumn('Session', 'session_id', false);
		$listing->addColumn('IP Address', 'ip_addr', false);
		$listing->addColumn('User Agent', 'useragent', false);
		$listing->addColumn('Generation', 'processing_time', false);
		$listing->addColumn('DB Reads', 'db_reads', false);
		$listing->addColumn('DB Writes', 'db_writes', false);
		
		$listing->setModelName('UserActivityModel');
		$listing->setDefaultSort('datetime', 'DESC');

		$listing->loadFiltersFromRequest($request);

		$view->title = 'User Activity Details';
		$view->assign('listings', $listing);
	}
예제 #6
0
	public function view(){
		$v = $this->getView();

		$pages = PageModel::Find(array('admin' => '1'));
		$groups = array();
		$flatlist = array();

		if(isset($_SESSION['user_sudo'])){
			$p = new PageModel('/user/sudo');
			$p->set('title', 'Exit SUDO Mode');
			$groups['SUDO'] = [
				'title' => 'SUDO',
				'href' => '',
				'children' => [
					'Exit SUDO Mode' => $p,
				],
			];
			$flatlist[ 'Exit SUDO Mode' ] = $p;
		}


		if(\Core\user()){
			foreach($pages as $p){
				/** @var PageModel $p */
				if(!\Core\user()->checkAccess($p->get('access'))) continue;

				// Pages can define which sub-menu they get grouped under.
				// The 'Admin' submenu is the default.
				$group = $p->get('admin_group') ? $p->get('admin_group') : 't:STRING_ADMIN';
				// Support i18n here!
				if(strpos($group, 't:') === 0){
					$group = t(substr($group, 2));
				}

				if(!isset($groups[$group])){
					$groups[$group] = [
						'title'    => $group,
						'href'     => '',
						'children' => [],
					];
				}

				if($p->get('baseurl') == '/admin'){
					// Admin gets special treatment.
					$groups[t('STRING_ADMIN')]['href'] = '/admin';
					continue;
				}

				switch($p->get('title')){
					case 'System Configuration':
						$p->set('title', "System Config");
						break;
					case 'Navigation Listings':
						$p->set('title', "Navigation");
						break;
					case 'Content Page Listings':
						$p->set('title', "Content Pages");
						break;
					default:
						$p->set(
							'title',
							trim( str_replace(['Administration', 'Admin'],'', $p->get('title')) )
						);
				}

				$title = $p->get('title');
				// Support i18n here!
				if(strpos($title, 't:') === 0){
					$title = t(substr($title, 2));
				}

				if(isset($groups[$title])){
					// Link the main group to this page instead of an empty link.
					// This removes duplicate links such as the group "User" and page "User".
					$groups[$title]['href'] = $p->get('rewriteurl');
				}
				else{
					// The new grouped pages
					$groups[$group]['children'][ $title ] = $p;
					// And the flattened list to support legacy templates.
					$flatlist[ $title ] = $p;
				}
			}

			// This is a hack to make sure that users can view the /admin link if they can view other admin pages.
			/*if(sizeof($flatlist) && !isset($groups['Admin']['Dashboard'])){
				$p = new PageModel('/admin');
				$p->set('title', 'Dashboard');
				$groups['Admin']['Dashboard'] = $p;
			}*/
		}

		ksort($flatlist);
		ksort($groups);

		foreach($groups as $gname => $dat){
			ksort($groups[$gname]['children']);
		}

		// Build a list of languages that can be set by the user.
		$locales = \Core\i18n\I18NLoader::GetLocalesEnabled();
		$selected = \Core\i18n\I18NLoader::GetUsersLanguage();
		$languages = [];
		if(sizeof($locales) > 1){
			// There is at least 1 language available on the system, YAY!
			foreach($locales as $localeKey => $localeDat){
				if(($pos = strpos($localeKey, '_')) !== false){
					// This locale contains an underscore, that means it has a corresponding country!
					// These are what we want to display to the end user.
					$country = substr($localeKey, $pos+1);

					// Here I am retrieving the language and dialect in the native dialect if at all possible.
					// This is because if you as a user only can read your native language and your browser renders something different,
					// then you want to be able to read what you're switching it to.
					$str1 = new \Core\i18n\I18NString($localeDat['lang']);
					$str1->setLanguage($localeKey);
					$localeTitle = $str1->getTranslation();
					if($localeDat['dialect']){
						$str2 = new \Core\i18n\I18NString($localeDat['dialect']);
						$str2->setLanguage($localeKey);
						$localeTitle .= ' (' . $str2->getTranslation() . ')';
					}

					$languages[] = [
						'key'      => $localeKey,
					    'title'    => $localeTitle,
					    'country'  => $country,
					    'image'    => 'assets/images/iso-country-flags/' . strtolower($country) . '.png',
					    'selected' => $localeKey == $selected,
					];
				}
			}
		}

		$v->templatename = 'widgets/adminmenu/view.tpl';
		$v->assign('pages', $flatlist);
		$v->assign('groups', $groups);
		$v->assign('languages', $languages);

		return $v;
	}
예제 #7
0
	/**
	 * Execute the controller and method this page request points to.
	 */
	public function execute() {

		\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Starting PageRequest->execute()');

		if($this->isCacheable()){
			$uakey = \Core\UserAgent::Construct()->getPseudoIdentifier();
			$urlkey = $this->host . $this->uri;
			$expires = $this->getPageModel()->get('expires');
			$key = 'page-cache-' . md5($urlkey . '-' . $uakey);

			$cached = \Core\Cache::Get($key, $expires);
			if($cached && $cached instanceof View){
				$this->_pageview = $cached;
				$this->_cached = true;
				return;
			}
		}

		// Anything that needs to fire off *before* the page is rendered.
		// This includes widgets, script addons, and anything else that needs a CurrentPage.
		HookHandler::DispatchHook('/core/page/preexecute');

		// Load the underlying controller.
		$pagedat   = $this->splitParts();

		/** @var View $view The valid view object for this page */
		$view = $this->getView();

		// The controller must exist first!
		// (note, the SplitParts logic already takes care of the "Is this a valid controller" logic)
		if (!(isset($pagedat['controller']) && $pagedat['controller'])) {
			$view->error = View::ERROR_NOTFOUND;
			return;
		}

		$component = Core::GetComponentByController($pagedat['controller']);

		//////////////////////////////////////////////////////////////////////////////
		///  In this block of logic, either the page is executed and a view returned,
		///  or a view is generated with an error.
		//////////////////////////////////////////////////////////////////////////////
		if (!$component) {
			// Not found
			$view->error = View::ERROR_NOTFOUND;
			return;
		}
		elseif(!is_a($component, 'Component_2_1')) {
			$view->error = View::ERROR_NOTFOUND;
			return;
		}

		// Any method that starts with a "_" is an internal-only method!
		if ($pagedat['method']{0} == '_') {
			$view->error = View::ERROR_NOTFOUND;
			return;
		}

		// It also must be a part of the class... obviously
		if (!method_exists($pagedat['controller'], $pagedat['method'])) {
			$view->error = View::ERROR_NOTFOUND;
			return;
		}


		/** @var $controller Controller_2_1 This will be a Controller object. */
		$controller = Controller_2_1::Factory($pagedat['controller']);

		$view->baseurl = $this->getBaseURL();
		$controller->setView($view);

		// Make sure that the controller can access this object.
		$controller->setPageRequest($this);

		// The main page object.
		$page = $this->getPageModel();

		// Check the access string first, (if there is one)
		if ($controller->accessstring !== null) {
			// Update the page's access string, (just in case it's saved at the end of execution)
			$page->set('access', $controller->accessstring);

			// And if the user doesn't have access to it...
			if (!\Core\user()->checkAccess($controller->accessstring)) {
				$view->error = View::ERROR_ACCESSDENIED;
				return;
			}
		}

		if($page->get('password_protected')) {
			if(\Core\Session::Get('page-password-protected/' . $page->get('baseurl')) !== $page->get('password_protected')){
				$view->templatename = '/pages/page/passwordprotected.tpl';

				$form = new Form();

				$form->set('callsmethod', 'PageRequest::PasswordProtectHandler');
				$form->addElement(
					'system', [
						'name'  => 'page',
						'value' => $page
					]
				);

				$form->addElement(
					'password', [
						'name'      => 'passinput',
						'title'     => 'Password',
						'required'  => 'required',
						'maxlength' => 128
					]
				);
				$form->addElement(
					'submit', [
						'value' => 'Submit'
					]
				);

				$view->assign('form', $form);

				return;
			}
		}

		// If the parent Controller object has a method named $pagedat['method'], assume it's a security error!
		// This is because if the parent Controller object has a method, it's most likely a utility method
		// that shouldn't be called from the public web!
		foreach(get_class_methods('Controller_2_1') as $parentmethod){
			$parentmethod = strtolower($parentmethod);
			if($parentmethod == $pagedat['method']){
				$view->error = View::ERROR_BADREQUEST;
				return;
			}
		}

		// Additional security logic for existing pages in multi-site mode.
		// If this exact URL is registered to another site, then
		// don't allow this site to display it.
		if(!$page->exists() && Core::IsComponentAvailable('multisite') && MultiSiteHelper::IsEnabled()){
			$site = MultiSiteHelper::GetCurrentSiteID();

			$anypage = PageModel::Find(['baseurl = ' . $page->get('baseurl')], 1);

			if($anypage){

				if($anypage->get('site') == -1){
					// If this is a global page.... that's ok.
					// Just remap the page variable to this one!
					$page = $anypage;
				}
				elseif($anypage->get('site') == $site){
					// Strange... it should have located this page...
					// Anyway, it's allowed, the site matches up.
					$page = $anypage;
				}
				else{
					\Core\redirect($anypage->getResolvedURL());
				}
			}
		}

		$return = call_user_func(array($controller, $pagedat['method']));
		if (is_int($return)) {
			// A generic error code was returned.  Create a View with that code and return that instead.
			$view->error = $return;
			//return;
		}
		elseif(is_a($return, 'View') && $return != $view){
			// The controller method changed the view, (which is allowed),
			// but this needs to be remapped to this object so render knows about it.
			$this->_pageview = $view = $return;
		}
		elseif ($return === null) {
			// Hopefully it's setup!
			$return = $controller->getView();
			if($return != $view){
				$this->_pageview = $view = $return;
			}
		}
		elseif(!is_a($return, 'View')){
			if(DEVELOPMENT_MODE){
				var_dump('Controller method returned', $return);
				die('Sorry, but this controller did not return a valid object.  Please ensure that your method returns either an integer, null, or a View object!');
			}
			else{
				$view->error = View::ERROR_SERVERERROR;
				return;
			}
		}
		// No else needed, else it's a valid object.


		// You may be asking why $view is one object, but $return is the return from page execution.
		// GREAT QUESTION, The $view is the original view object created from the page request.  That is passed into
		// the controller and exposed via $this->getView().  The return can be a view, int, or other status indicator.
		// However since the controller can return a different view, that view should be used instead!
		///** @var $return View */


		// Allow the controller to assign controls via a shortcut function.
		if($view->error == View::ERROR_NOERROR){
			$controls = $controller->getControls();

			// This method may do absolutely nothing, add the controls to the view itself, or return an array of them.
			if(is_array($controls)){
				foreach($controls as $control){
					$view->addControl($control);
				}
			}
		}


		// For some of the options, there may be some that can be used for a fuzzy page, ie: a page's non-fuzzy template,
		// title, or meta information.
		if($view->error == View::ERROR_NOERROR){
			if ($page->exists()) {
				$defaultpage = $page;
			} else {
				$defaultpage = null;
				$url         = $view->baseurl;
				while ($url != '') {
					$url = substr($url, 0, strrpos($url, '/'));
					$p   = PageModel::Find(array('baseurl' => $url, 'fuzzy' => 1), 1);
					if ($p === null) continue;
					if ($p->exists()) {
						$defaultpage = $p;
						break;
					}
				}
				if ($defaultpage === null) {
					// Fine....
					$defaultpage = $page;
				}
			}

			$defaultmetas = $defaultpage->getLink('PageMeta');

			// Make a list of the existing ones so I know which ones not to overwrite!
			// Just the key will suffice quite nicely.
			$currentmetas = array();
			foreach($view->meta as $k => $meta){
				$currentmetas[] = $k;
			}

			// Load some of the page information into the view now!
			foreach($defaultmetas as $meta){
				/** @var $meta PageMetaModel */
				$key = $meta->get('meta_key');

				$viewmeta = $meta->getViewMetaObject();

				// again, allow the executed controller have the final say on meta information.
				if ($meta->get('meta_value_title') && !in_array($key, $currentmetas)) {
					$view->meta[$key] = $viewmeta;
				}
			}


			// Since the controller already ran, do not overwrite the title.
			if ($view->title === null){
				$view->title = $defaultpage->get('title');
			}

			// Tracker to see if this page, (or a parent's page), is an admin-level page.
			// This is required because "admin" pages may have a different skin and should always have the dashboard as the top-level breadcrumb.
			/** @var boolean $isadmin */
			$isadmin = ($page->get('admin') == '1');

			$parents = array();
			$parenttree = $page->getParentTree();
			foreach ($parenttree as $parent) {
				/** @var PageModel $parent */
				$parents[] = array(
					'title' => $parent->get('title'),
					'link'  => $parent->getResolvedURL()
				);

				// Since I'm here, check if this page is an admin page.
				if($parent->get('admin')){
					$isadmin = true;
				}
			}
			$view->breadcrumbs = array_merge($parents, $view->breadcrumbs);

			if($isadmin && $view->baseurl != '/admin'){
				// Make sure that admin is the top breadcrumb.
				// This block doesn't need to apply for the actual admin page itself, as that doesn't need its own breadcrumb :/
				$adminlink = \Core\resolve_link('/admin');
				if(!isset($view->breadcrumbs[0])){
					// Nothing is even set!
					$view->breadcrumbs[] = ['title' => 'Administration', 'link' => $adminlink];
				}
				elseif($view->breadcrumbs[0]['link'] != $adminlink){
					// It's set, but not to admin.
					$view->breadcrumbs = array_merge([['title' => 'Administration', 'link' => $adminlink]], $view->breadcrumbs);
				}
			}
		}
		else{
			$defaultpage = null;
			$isadmin = false;
		}


		if(
			$view->mode == View::MODE_PAGEORAJAX &&
			$this->isAjax() &&
			$view->jsondata !== null &&
			$view->templatename === null
		){
			// Allow the content type to be overridden for ajax pages that have JSON data embedded in them.
			$view->contenttype = View::CTYPE_JSON;
		}


		if($view->mode == View::MODE_NOOUTPUT){
			$view->mastertemplate = false;
			$view->templatename = null;
		}
		elseif(
			$view->error == View::ERROR_NOERROR &&
			$view->contenttype == View::CTYPE_HTML &&
			$view->templatename === null
		){
			// Try to guess the templatename if it wasn't set.
			// This
			$cnameshort           = (strpos($pagedat['controller'], 'Controller') == strlen($pagedat['controller']) - 10) ? substr($pagedat['controller'], 0, -10) : $pagedat['controller'];
			$view->templatename = strtolower('/pages/' . $cnameshort . '/' . $pagedat['method'] . '.tpl');
		}
		elseif(
			$view->error == View::ERROR_NOERROR &&
			$view->contenttype == View::CTYPE_XML &&
			$view->templatename === null
		){
			$cnameshort           = (strpos($pagedat['controller'], 'Controller') == strlen($pagedat['controller']) - 10) ? substr($pagedat['controller'], 0, -10) : $pagedat['controller'];
			$view->templatename = Template::ResolveFile(strtolower('pages/' . $cnameshort . '/' . $pagedat['method'] . '.xml.tpl'));
		}

		// In addition to the autogeneration, also support the page_template from the datastore.
		if($defaultpage && $defaultpage->get('page_template')){
			// Switch the template over to that custom one.
			// Some legacy data will have the fully resolved path for this template.
			// This has been switched to just the basename of the custom template,
			// but legacy data be legacy, 'yo.                            0.o

			$base     = substr($view->templatename, 0, -4);
			$override = $defaultpage->get('page_template');
			if($base && strpos($override, $base) === 0){
				$view->templatename = $override;
			}
			elseif($base){
				$view->templatename = $base . '/' . $override;
			}
		}

		// Guess which theme skin (mastertemplate) should be used if one wasn't specified.
		if($view->mastertemplate == 'admin'){
			// If the master template is set explictly to be the admin skin, then transpose that to the set admin skin.
			// This is useful for the pages that may not be under the "/admin" umbrella, but still rendered with the admin UI.
			$view->mastertemplate = ConfigHandler::Get('/theme/default_admin_template');
		}
		elseif($view->mastertemplate){
			// No change needed, just skip the below cases.
		}
		elseif($view->mastertemplate === false){
			// If the master template is explictly set to false, the page wanted no master template!
		}
		elseif($isadmin){
			// This page doesn't have a master template set, but it or a parent is set as an admin-level page.
			$view->mastertemplate = ConfigHandler::Get('/theme/default_admin_template');
		}
		elseif ($defaultpage && $defaultpage->get('theme_template')) {
			// Master template set in the database?
			$view->mastertemplate = $defaultpage->get('theme_template');
		}
		elseif($defaultpage && $defaultpage->exists() && $defaultpage->get('admin')){
			// Or an admin level page?
			$view->mastertemplate = ConfigHandler::Get('/theme/default_admin_template');
		}
		elseif(sizeof($view->breadcrumbs) && $view->breadcrumbs[0]['title'] == 'Administration'){
			// Whatever, close e-damn-nough!
			// This happens for pages that don't actually exist, like "edit"....
			$view->mastertemplate = ConfigHandler::Get('/theme/default_admin_template');
		}
		else{
			$view->mastertemplate = ConfigHandler::Get('/theme/default_template');
		}

		// First of all, if the current theme is not available, reset back to the first theme available!
		if(!($theme = ThemeHandler::GetTheme())){
			/** @var \Theme\Theme $theme */
			$theme = ThemeHandler::GetTheme('base-v2');
			$view->mastertemplate = 'basic.tpl';
			\Core\set_message('t:MESSAGE_ERROR_INVALID_THEME_SELECTED');
		}

		// Make sure the selected mastertemplate actually exists!
		if($view->mastertemplate !== false){
			$themeskins = $theme->getSkins();
			$mastertplgood = false;
			foreach($themeskins as $skin){
				if($skin['file'] == $view->mastertemplate){
					// It's located!
					$mastertplgood =true;
					break;
				}
			}

			// A few special cases.
			if($view->mastertemplate == 'blank.tpl'){
				// This is acceptable as a default one.
				$mastertplgood =true;
			}

			if(!$mastertplgood){
				// Just use the first one instead!
				trigger_error('Invalid skin [' . $view->mastertemplate . '] selected for this page, skin is not located within the selected theme!  Using first available instead.', E_USER_NOTICE);
				$view->mastertemplate = $themeskins[0]['file'];
			}
		}

		// Handle some of the new automatic meta data associated with Pages and the resulting View.

		if(\ConfigHandler::Get('/core/page/indexable') == 'deny'){
			// Administratively set to noindex on all pages.
			$view->addMetaName('robots', 'noindex');
		}
		elseif(!$page->get('indexable')){
			// Bots have no business indexing user-action pages.
			$view->addMetaName('robots', 'noindex');
		}
		if(!isset($view->meta['title'])){
			$view->meta['title'] = $page->getSEOTitle();
		}

		HookHandler::DispatchHook('/core/page/postexecute');

		\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Completed PageRequest->execute()');
	}
예제 #8
0
 /**
  * This is a widget to display children of the current page
  *
  * The page is dynamic based on the currently viewed page.
  *
  * @return int
  */
 public function children()
 {
     $view = $this->getView();
     $current = PageRequest::GetSystemRequest();
     $model = $current->getPageModel();
     if (!$model) {
         return '';
     }
     $baseurl = $model->get('baseurl');
     // Give me all the siblings of that baseurl.
     $pages = PageModel::Find(['parenturl' => $baseurl, 'selectable' => 1], null, 'title');
     $entries = [];
     foreach ($pages as $page) {
         $subpages = PageModel::Find(['parenturl' => $page->get('baseurl'), 'selectable' => 1], null, 'title');
         $subentries = [];
         foreach ($subpages as $subpage) {
             $subentries[] = ['obj' => $subpage, 'children' => [], 'class' => ''];
         }
         $entries[] = ['obj' => $page, 'children' => $subentries, 'class' => 'active'];
     }
     $view->assign('entries', $entries);
 }
<?php

/**
 * Created by JetBrains PhpStorm.
 * User: powellc
 * Date: 1/17/13
 * Time: 10:20 PM
 * This is the upgrade file from 1.3.0 to 1.4.0
 *
 * Now that core supports selectable and non-selectable pages, I need to update all the existing blog articles to make them not selectable.
 */
$pages = PageModel::Find(array('baseurl LIKE /blog/article/view/%'));
foreach ($pages as $page) {
    $page->set('selectable', 0);
    $page->save();
}
// return
 /**
  * Hook to check for any new files in the system and register pages (or deregister them as necessary).
  * 
  * Only runs if the config option is enabled to do so.
  */
 public static function _AutoRegisterFiles()
 {
     if (!\ConfigHandler::Get('/markdownbrowser/autoregister')) {
         echo 'Skipping autoregistration of markdown files, configuration option for this feature is disabled.' . "\n";
         return true;
     }
     $dir = \ConfigHandler::Get('/markdownbrowser/basedir');
     $markdownFiles = [];
     if (!$dir) {
         echo 'Skipping autoregistration of markdown files, no markdown directory configured.' . "\n";
         return true;
     }
     // Make sure it's readable!
     $dir = \Core\Filestore\Factory::Directory($dir);
     $dirbase = $dir->getPath();
     $dirlen = strlen($dirbase);
     if (!$dir->exists()) {
         echo 'Skipping autoregistration of markdown files, ' . $dir->getPath() . ' does not exist.' . "\n";
         return true;
     }
     $all = [];
     $files = $dir->ls('md', true);
     foreach ($files as $file) {
         /** @var \Core\Filestore\File $file */
         $fileBase = substr($file->getFilename(), $dirlen);
         if (strpos($fileBase, 'index.md') !== false) {
             $fileRel = substr($fileBase, 0, -8);
         } else {
             $fileRel = substr($fileBase, 0, -3);
         }
         if (preg_match('/[A-Z]/', $fileRel) !== 0) {
             $warning = t('STRING_MARKDOWNBROWSER_WARNING_FILE_HAS_CAPITALS');
         } elseif (strpos($fileRel, ' ')) {
             $warning = t('STRING_MARKDOWNBROWSER_WARNING_FILE_HAS_SPACES');
         } else {
             $warning = '';
         }
         if ($warning == '') {
             $url = '/markdownbrowser/view/' . $fileRel;
             $all[$url] = ['file' => $file, 'page' => null];
         } else {
             echo $warning . ' - ' . $fileRel . "\n";
         }
     }
     // Now that the files are loaded into memory, load any page that may already exist.
     // This will be used to ignore entries that already have a page, to create ones without,
     // and to remove pages that no longer have a corresponding file.
     $pages = PageModel::Find(['baseurl LIKE /markdownbrowser/view%']);
     foreach ($pages as $p) {
         $url = $p->get('baseurl');
         if (!isset($all[$url])) {
             $all[$url] = ['file' => null, 'page' => null];
         }
         $all[$url]['page'] = $p;
     }
     // Now $all contains everything I need to process on! :)
     foreach ($all as $url => &$dat) {
         /** @var PageModel|null $page */
         $page = $dat['page'];
         /** @var \Core\Filestore\File|null $file */
         $file = $dat['file'];
         if ($page && !$file) {
             // There is a page but no file, DELETE!
             $page->delete();
             echo 'Deleted page for non-existent file: ' . $url . "\n";
         } elseif (!$page && $file) {
             // There is a file but no page, create.
             $contents = $file->getContents();
             // Convert these contents from markdown to HTML.
             $processor = new \Core\MarkdownProcessor();
             $html = $processor->transform($contents);
             // Pre-populate this page with information from the rendered markdown document.
             // If this page exists, then it'll be updated and kept in sync.
             // Else, it'll still be set with what's in the document and kept in sync.
             $page = PageModel::Construct($url);
             $page->set('title', $processor->getMeta('title'));
             $page->set('body', $html);
             $page->set('baseurl', $url);
             $page->set('rewriteurl', $url);
             $page->set('editurl', str_replace('/markdownbrowser/view', '/markdownbrowser/update', $url));
             $page->set('component', 'markdown-browser');
             $page->set('selectable', 1);
             $page->set('published', $file->getMTime());
             $page->set('updated', $file->getMTime());
             $page->set('created', $file->getMTime());
             $page->save();
             echo 'Created page for new file: ' . $url . "\n";
         }
     }
     return true;
 }