/** * Page to view and test the i18n settings and strings of this site. * * Also useful for viewing what strings are currently installed and where they came from! * * @return int */ public function i18n(){ $view = $this->getView(); $request = $this->getPageRequest(); if(!\Core\user()->checkAccess('g:admin')){ // This test page is an admin-only utility. return View::ERROR_ACCESSDENIED; } /*$locales = Core\i18n\I18NLoader::GetLocalesAvailable(); // Languages will be the current languages/locales available on the system. $languages = []; foreach($locales as $lang => $dat){ if(strpos($lang, '_') !== false){ $base = substr($lang, 0, strpos($lang, '_')); if(!isset($languages[$base])){ // Add the base language, (useful here because the editor may want to edit only the base language and not specific dialects). $languages[$base] = t($dat['lang']); } } $languages[$lang] = t($dat['lang']) . (($dat['dialect']) ? ' (' . t($dat['dialect']) . ')' : ''); }*/ // I need to use GetLocalesAvailable because the higher level functions will only return what's currently enabled, // which is the entire point of this page! $locales = Core\i18n\I18NLoader::GetLocalesAvailable(); // Make this full list a more flat list suitable for populating directly into the form element. $all = []; foreach($locales as $key => $dat){ $all[$key] = t($dat['lang']) . ' (' . t($dat['dialect']) . ')'; } $enabled = \ConfigHandler::Get('/core/language/languages_enabled'); // This is expected to be a pipe-seperated list of languages/locales enabled. $enabled = array_map('trim', explode('|', $enabled)); // Did the user request a specific language? $requested = $request->getParameter('lang'); if($requested){ $showStrings = false; $showForm = true; } else{ $showStrings = true; $showForm = false; $requested = \Core\i18n\I18NLoader::GetUsersLanguage(); } $strings = \Core\i18n\I18NLoader::GetAllStrings($requested); $form = new Form(); $form->set('callsmethod', 'AdminController::_i18nSaveHandler'); $form->addElement( 'checkboxes', [ 'name' => 'languages[]', 'title' => t('STRING_CONFIG_CORE_LANGUAGE_LANGUAGES_ENABLED'), 'description' => t('MESSAGE_CONFIG_CORE_LANGUAGE_LANGUAGES_ENABLED'), 'options' => $all, 'value' => $enabled, ] ); /* $form->addElement('system', ['name' => 'lang', 'value' => $requested]); foreach($strings as $dat){ $type = strpos($dat['key'], 'MESSAGE_') === 0 ? 'textarea' : 'text'; $form->addElement( $type, [ 'name' => $dat['key'], 'title' => $dat['key'], 'value' => $dat['found'] ? $dat['match_str'] : '', 'description' => $dat['results']['DEFAULT'] ? $dat['results']['DEFAULT'] : $dat['results']['FALLBACK'], ] ); } */ $form->addElement('submit', ['value' => t('STRING_SAVE')]); $view->addBreadcrumb('t:STRING_ADMIN', '/admin'); $view->title = 't:STRING_I18N_LANGUAGES'; //$view->assign('languages', $languages); $view->assign('form', $form); $view->assign('strings', $strings); $view->assign('show_strings', $showStrings); $view->assign('show_form', $showForm); $view->assign('requested', $requested); }
/** * Fetch this view as an HTML string. * @return mixed|null|string */ public function fetch() { if($this->_fetchCache !== null){ // w00t ;) return $this->_fetchCache; } try{ $body = $this->fetchBody(); \Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record( 'Fetched application content from within View->fetch() for ' . $this->templatename ); } catch(Exception $e){ $this->error = View::ERROR_SERVERERROR; \Core\ErrorManagement\exception_handler($e, ($this->mode == View::MODE_PAGE)); $body = ''; } // If there's no template, I have nothing to even do! if ($this->mastertemplate === false) { return $body; } // Else if it's null, it's just not set yet :p // @deprecated here! elseif ($this->mastertemplate === null) { $this->mastertemplate = ConfigHandler::Get('/theme/default_template'); } // Whee! //var_dump($this->templatename, Core\Templates\Template::ResolveFile($this->templatename)); // Content types take priority on controlling the master template. if ($this->contenttype == View::CTYPE_JSON) { $mastertpl = false; } else { // Master template depends on the render mode. switch ($this->mode) { case View::MODE_PAGEORAJAX: if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){ $mastertpl = false; $this->mode = View::MODE_AJAX; } else{ $mastertpl = ROOT_PDIR . 'themes/' . ConfigHandler::Get('/theme/selected') . '/skins/' . $this->mastertemplate; $this->mode = View::MODE_PAGE; } break; case View::MODE_NOOUTPUT: case View::MODE_AJAX: $mastertpl = false; break; case View::MODE_PAGE: case View::MODE_EMAILORPRINT: $mastertpl = Core\Templates\Template::ResolveFile('skins/' . $this->mastertemplate); //$mastertpl = ROOT_PDIR . 'themes/' . ConfigHandler::Get('/theme/selected') . '/skins/' . $this->mastertemplate; break; case View::MODE_WIDGET: $mastertpl = Core\Templates\Template::ResolveFile('widgetcontainers/' . $this->mastertemplate); break; } } // If there's *still* no template, I still have nothing to do. if (!$mastertpl) return $body; $template = \Core\Templates\Template::Factory($mastertpl); // Ensure that the template is linked to this View correctly. $template->setView($this); //$template = new Core\Templates\Template(); //$template->setBaseURL('/'); // Page-level views have some special variables. if ($this->mode == View::MODE_PAGE) { $template->assign('breadcrumbs', $this->getBreadcrumbs()); $template->assign('controls', $this->controls); $template->assign('messages', Core::GetMessages()); // Tack on the pre and post body variables from the current page. //$body = CurrentPage::GetBodyPre() . $body . CurrentPage::GetBodyPost(); } // Widgets need some special variables too. //if($this->mode == View::MODE_WIDGET){ // //var_dump($this->getVariable('widget')); die(); // $template->assign('widget', $this->getVariable('widget')); //} // This logic is needed for the SEO title, since that's usually completely human unfriendly. if(isset($this->meta['title']) && $this->meta['title']){ $template->assign('seotitle', $this->meta['title']); } else{ $template->assign('seotitle', $this->getTitle()); } $template->assign('title', $this->getTitle()); $template->assign('body', $body); // The body needs some custom classes for assisting the designers. // These are mainly pulled from the UA. $ua = \Core\UserAgent::Construct(); $this->bodyclasses = array_merge($this->bodyclasses, $ua->getPseudoIdentifier(true)); // Provide a way for stylesheets to target this page specifically. switch ($this->error) { case View::ERROR_BADREQUEST: case View::ERROR_PAYMENTREQUIRED: case View::ERROR_ACCESSDENIED: case View::ERROR_NOTFOUND: case View::ERROR_METHODNOTALLOWED: case View::ERROR_NOTACCEPTABLE: case View::ERROR_PROXYAUTHENTICATIONREQUIRED: case View::ERROR_REQUESTTIMEOUT: case View::ERROR_CONFLICT: case View::ERROR_GONE: case View::ERROR_LENGTHREQUIRED: case View::ERROR_PRECONDITIONFAILED: case View::ERROR_ENTITYTOOLARGE: case View::ERROR_URITOOLARGE: case View::ERROR_UNSUPPORTEDMEDIATYPE: case View::ERROR_RANGENOTSATISFIABLE: case View::ERROR_EXPECTATIONFAILED: case View::ERROR_UNAUTHORIZED: $url = 'error-' . $this->error; break; case 403: $url = "error-403 page-user-login"; break; default: $url = strtolower(trim(preg_replace('/[^a-z0-9\-]*/i', '', str_replace('/', '-', $this->baseurl)), '-')); } while($url != ''){ $this->bodyclasses[] = 'page-' . $url; $url = substr($url, 0, strrpos($url, '-')); } $bodyclasses = strtolower(implode(' ', $this->bodyclasses)); $template->assign('body_classes', $bodyclasses); try{ $data = $template->fetch(); } catch(SmartyException $e){ $this->error = View::ERROR_SERVERERROR; error_log('[view error]'); error_log('Template name: [' . $mastertpl . ']'); \Core\ErrorManagement\exception_handler($e); require(ROOT_PDIR . 'core/templates/halt_pages/fatal_error.inc.html'); die(); } catch(TemplateException $e){ $this->error = View::ERROR_SERVERERROR; error_log('[view error]'); error_log('Template name: [' . $mastertpl . ']'); \Core\ErrorManagement\exception_handler($e); require(ROOT_PDIR . 'core/templates/halt_pages/fatal_error.inc.html'); die(); } if($this->mode == View::MODE_EMAILORPRINT && $this->contenttype == View::CTYPE_HTML){ // Inform other elements that the page is just about to be rendered. HookHandler::DispatchHook('/core/page/rendering', $this); // Replace the </head> tag with the head data from the current page // and the </body> with the foot data from the current page. // This is needed to be done at this stage because some element in // the template after rendering may add additional script to the head. // Also tack on any attributes for the <html> tag. if(preg_match('#</head>#i', $data)){ // I need to do preg_replace because I only want to replace the FIRST instance of </head> $data = preg_replace('#</head>#i', $this->getHeadContent() . "\n" . '</head>', $data, 1); } } elseif ($this->mode == View::MODE_PAGE && $this->contenttype == View::CTYPE_HTML) { // Inform other elements that the page is just about to be rendered. HookHandler::DispatchHook('/core/page/rendering', $this); // Metadata! w00t // Replace the </head> tag with the head data from the current page // and the </body> with the foot data from the current page. // This is needed to be done at this stage because some element in // the template after rendering may add additional script to the head. // Also tack on any attributes for the <html> tag. if(preg_match('#</head>#i', $data)){ // I need to do preg_replace because I only want to replace the FIRST instance of </head> $data = preg_replace('#</head>#i', $this->getHeadContent() . "\n" . '</head>', $data, 1); } if(preg_match('#</body>#i', $data)){ // I need to use strrpos because I only want the LAST instance of </body> $match = strrpos($data, '</body>'); $foot = $this->getFootContent(); if(defined('ENABLE_XHPROF') && function_exists('xhprof_disable')){ require_once('xhprof_lib/utils/xhprof_lib.php'); #SKIPCOMPILER require_once('xhprof_lib/utils/xhprof_runs.php'); #SKIPCOMPILER $xhprof_data = xhprof_disable(); $namespace = trim(str_replace(['.', '/'], '-', HOST . REL_REQUEST_PATH), '-'); $xhprof_runs = new XHProfRuns_Default(); $run_id = $xhprof_runs->save_run($xhprof_data, $namespace); define('XHPROF_RUN', $run_id); define('XHPROF_SOURCE', $namespace); $xhprof_link = sprintf( '<a href="' . SERVERNAME . '/xhprof/index.php?run=%s&source=%s" target="_blank">View XHprof Profiler Report</a>' . "\n", $run_id, $namespace ); } else{ $xhprof_link = ''; } // If the viewmode is regular and DEVELOPMENT_MODE is enabled, show some possibly useful information now that everything's said and done. if (DEVELOPMENT_MODE) { $legend = '<div class="fieldset-title">%s<i class="icon-chevron-down expandable-hint"></i><i class="icon-chevron-up collapsible-hint"></i></div>' . "\n"; $debug = ''; $debug .= '<pre class="xdebug-var-dump screen">'; $debug .= '<fieldset class="debug-section collapsible" id="debug-section-template-information">'; $debug .= sprintf($legend, 'Template Information'); $debug .= "<span>"; $debug .= 'Base URL: ' . $this->baseurl . "\n"; $debug .= 'Template Requested: ' . $this->templatename . "\n"; $debug .= 'Template Actually Used: ' . \Core\Templates\Template::ResolveFile($this->templatename) . "\n"; $debug .= 'Master Skin: ' . $this->mastertemplate . "\n"; $debug .= "</span>"; $debug .= '</fieldset>'; $debug .= '<fieldset class="debug-section collapsible" id="debug-section-performance-information">'; $debug .= sprintf($legend, 'Performance Information'); $debug .= "<span>"; $debug .= $xhprof_link; $debug .= "Database Reads: " . \Core\Utilities\Profiler\DatamodelProfiler::GetDefaultProfiler()->readCount() . "\n"; $debug .= "Database Writes: " . \Core\Utilities\Profiler\DatamodelProfiler::GetDefaultProfiler()->writeCount() . "\n"; //$debug .= "Number of queries: " . DB::Singleton()->counter . "\n"; //$debug .= "Amount of memory used by PHP: " . \Core\Filestore\format_size(memory_get_usage()) . "\n"; $debug .= "Amount of memory used by PHP: " . \Core\Filestore\format_size(memory_get_peak_usage(true)) . "\n"; $profiler = Core\Utilities\Profiler\Profiler::GetDefaultProfiler(); $debug .= "Total processing time: " . $profiler->getTimeFormatted() . "\n"; $debug .= "</span>"; $debug .= '</fieldset>'; $debug .= '<fieldset class="debug-section collapsible" id="debug-section-profiler-information">'; $debug .= sprintf($legend, 'Core Profiler'); $debug .= "<span>"; $debug .= $profiler->getEventTimesFormatted(); $debug .= "</span>"; $debug .= '</fieldset>'; $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-components-information">'; // Tack on what components are currently installed. $debug .= sprintf($legend, 'Available Components'); $debugcomponents = array_merge(Core::GetComponents(), Core::GetDisabledComponents()); $debug .= "<span>"; // Give me sorting! ksort($debugcomponents); foreach ($debugcomponents as $l => $v) { if($v->isEnabled() && $v->isReady()){ $debug .= '[<span style="color:green;">Enabled</span>]'; } elseif($v->isEnabled() && !$v->isReady()){ $debug .= '[<span style="color:red;">!ERROR!</span>]'; } else{ $debug .= '[<span style="color:red;">Disabled</span>]'; } $debug .= $v->getName() . ' ' . $v->getVersion() . "<br/>"; } $debug .= "</span>"; $debug .= '</fieldset>'; $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-hooks-information">'; // I wanna see what hooks are registered too! $debug .= sprintf($legend, 'Registered Hooks'); foreach(HookHandler::GetAllHooks() as $hook){ $debug .= "<span>"; /** @var $hook Hook */ $debug .= $hook->name; if($hook->description) $debug .= ' <em> - ' . $hook->description . '</em>'; $debug .= "\n" . '<span style="color:#999;">Return expected: ' . $hook->returnType . '</span>'; $debug .= "\n" . '<span style="color:#999;">Attached by ' . $hook->getBindingCount() . ' binding(s).</span>'; foreach($hook->getBindings() as $b){ $debug .= "\n" . ' * ' . $b['call']; } $debug .= "\n\n"; $debug .= "</span>"; } $debug .= '</fieldset>'; // Display the licensed content on this application $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-licenser-information">'; $debug .= sprintf($legend, 'Licensed Information'); $lic = \Core\Licenser::GetRaw(); $debug .= '<div>'; foreach($lic as $dat){ $debug .= $dat['url'] . '::' . $dat['feature'] . ' => ' . $dat['value'] . "\n"; } $debug .= '</div></fieldset>'; $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-includes-information">'; // I want to see how many files were included. $debug .= sprintf($legend, 'Included Files'); $debug .= '<span>Number: ' . sizeof(get_included_files()) . "</span>"; $debug .= '<span>'. implode("<br/>", get_included_files()) . "</span>"; $debug .= '</fieldset>'; $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-query-information">'; $debug .= sprintf($legend, 'Query Log'); $profiler = \Core\Utilities\Profiler\DatamodelProfiler::GetDefaultProfiler(); $debug .= '<div>' . $profiler->getEventTimesFormatted() . '</div>'; $debug .= '</fieldset>'; // Display all the i18n strings available on the system. $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-i18nstrings-information">'; $debug .= sprintf($legend, 'I18N Strings Available'); $strings = \Core\i18n\I18NLoader::GetAllStrings(); $debug .= '<ul>'; foreach($strings as &$s){ $debug .= '<li>' . $s['key'] . '</li>'; } $debug .= '</ul>'; $debug .= '</fieldset>'; $debug .= '</pre>'; // And append! $foot .= "\n" . $debug; } $data = substr_replace($data, $foot . "\n" . '</body>', $match, 7); } $data = preg_replace('#<html#', '<html ' . $this->getHTMLAttributes(), $data, 1); // This logic has been migrated to the {$body_classes} variable. /* if(preg_match('/<body[^>]*>/', $data, $matches)){ // body is $matches[0]. $fullbody = $matches[0]; if($fullbody == '<body>'){ $body = '<body class="' . $bodyclass . '">'; } elseif(strpos($fullbody, 'class=') === false){ // Almost as easy, other elements but no class. $body = substr($fullbody, 0, -1) . ' class="' . $bodyclass . '">'; } else{ // parsing HTML is far easier with XML objects. $node = new SimpleXMLElement($fullbody . '</body>'); $body = '<body'; foreach($node->attributes() as $k => $v){ if($k == 'class'){ $body .= ' ' . $k . '="' . $bodyclass . ' ' . $v . '"'; } else{ $body .= ' ' . $k . '="' . $v . '"'; } } $body .= '>'; } // And replace! $data = preg_replace('#<body[^>]*>#', $body, $data, 1); } */ } $this->_fetchCache = $data; return $data; }