N°8772 - Turbo WIP

This commit is contained in:
Eric Espie
2025-10-29 16:52:19 +01:00
parent c00bcbcd81
commit 06dbdcb5cd
4 changed files with 55 additions and 65 deletions

View File

@@ -56,11 +56,11 @@ use ZipArchive;
abstract class Controller extends AbstractController
{
const ENUM_PAGE_TYPE_HTML = 'html';
const ENUM_PAGE_TYPE_BASIC_HTML = 'basic_html';
const ENUM_PAGE_TYPE_AJAX = 'ajax';
const ENUM_PAGE_TYPE_HTML = 'html';
const ENUM_PAGE_TYPE_BASIC_HTML = 'basic_html';
const ENUM_PAGE_TYPE_AJAX = 'ajax';
const ENUM_PAGE_TYPE_TURBO_FORM_AJAX = 'turbo_ajax';
const ENUM_PAGE_TYPE_SETUP = 'setup';
const ENUM_PAGE_TYPE_SETUP = 'setup';
/** @var \Twig\Environment */
private $oTwig;
@@ -190,12 +190,10 @@ abstract class Controller extends AbstractController
$sModulePath = dirname(dirname($this->GetDir()));
$this->SetModuleName(basename($sModulePath));
$this->SetViewPath($sModulePath.'/view');
try
{
try {
$this->aDefaultParams = array('sIndexURL' => utils::GetAbsoluteUrlModulePage($this->m_sModule, 'index.php'));
}
catch (Exception $e)
{
catch (Exception $e) {
IssueLog::Error($e->getMessage());
}
}
@@ -245,8 +243,7 @@ abstract class Controller extends AbstractController
*/
public function HandleOperation()
{
try
{
try {
$this->CheckAccess();
$this->m_sOperation = utils::ReadParam('operation', $this->sDefaultOperation);
@@ -261,8 +258,7 @@ abstract class Controller extends AbstractController
$this->DisplayBadRequest();
}
catch (Exception $e)
{
catch (Exception $e) {
http_response_code(500);
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
@@ -280,8 +276,7 @@ abstract class Controller extends AbstractController
*/
public function HandleAjaxOperation()
{
try
{
try {
$this->CheckAccess();
$this->m_sOperation = utils::ReadParam('operation', $this->sDefaultOperation);
@@ -296,8 +291,7 @@ abstract class Controller extends AbstractController
$this->DisplayPageNotFound();
}
catch (Exception $e)
{
catch (Exception $e) {
http_response_code(500);
$aResponse = array('sError' => $e->getMessage());
echo json_encode($aResponse);
@@ -312,6 +306,7 @@ abstract class Controller extends AbstractController
}
$this->$sMethodName();
return true;
}
@@ -334,13 +329,12 @@ abstract class Controller extends AbstractController
}
/**
* @since 3.0.0 N°3606 - Adapt TwigBase Controller for combodo-monitoring extension
* @throws \Exception
* @since 3.0.0 N°3606 - Adapt TwigBase Controller for combodo-monitoring extension
*/
protected function CheckAccess()
{
if ($this->bCheckDemoMode && MetaModel::GetConfig()->Get('demo_mode'))
{
if ($this->bCheckDemoMode && MetaModel::GetConfig()->Get('demo_mode')) {
throw new Exception("Sorry, iTop is in <b>demonstration mode</b>: this feature is disabled.");
}
@@ -348,31 +342,30 @@ abstract class Controller extends AbstractController
$sConfiguredAccessTokenValue = empty($this->sAccessTokenConfigParamId) ? "" : trim(MetaModel::GetConfig()->GetModuleSetting($sExecModule, $this->sAccessTokenConfigParamId));
if (empty($sExecModule) || empty($sConfiguredAccessTokenValue)){
if (empty($sExecModule) || empty($sConfiguredAccessTokenValue)) {
LoginWebPage::DoLogin($this->bMustBeAdmin);
} else {
//token mode without login required
//N°7147 - Error HTTP 500 due to access_token not URL decoded
$sPassedToken = utils::ReadPostedParam($this->sAccessTokenConfigParamId, null, false, 'raw_data');
if (is_null($sPassedToken)){
if (is_null($sPassedToken)) {
$sPassedToken = utils::ReadParam($this->sAccessTokenConfigParamId, null, false, 'raw_data');
}
$sDecodedPassedToken = urldecode($sPassedToken);
if ($sDecodedPassedToken !== $sConfiguredAccessTokenValue){
if ($sDecodedPassedToken !== $sConfiguredAccessTokenValue) {
$sMsg = "Invalid token passed under '$this->sAccessTokenConfigParamId' http param to reach '$sExecModule' page.";
IssueLog::Error($sMsg, null,
[
'sHtmlDecodedToken' => $sDecodedPassedToken,
'conf param ID' => $this->sAccessTokenConfigParamId,
'conf param ID' => $this->sAccessTokenConfigParamId,
]
);
throw new Exception("Invalid token");
}
}
if (!empty($this->sMenuId))
{
if (!empty($this->sMenuId)) {
ApplicationMenu::CheckMenuIdEnabled($this->sMenuId);
}
}
@@ -482,7 +475,7 @@ abstract class Controller extends AbstractController
$this->DisplayPage($aParams, $sTemplateName, 'setup');
}
public function DisplayTurboAjaxPage ($aParams = array(), $sTemplateName = 'turbo-ajax-update.html.twig')
public function DisplayTurboAjaxPage($aParams = array(), $sTemplateName = 'turbo-ajax-update.html.twig')
{
$this->DisplayPage($aParams, $sTemplateName, self::ENUM_PAGE_TYPE_TURBO_FORM_AJAX);
}
@@ -498,7 +491,7 @@ abstract class Controller extends AbstractController
*
* @throws \Exception
*/
public function DisplayPage($aParams = array(), $sTemplateName = null, $sPageType = 'html')
public function DisplayPage($aParams = array(), $sTemplateName = null, $sPageType = self::ENUM_PAGE_TYPE_HTML)
{
if (empty($sTemplateName)) {
$sTemplateName = $this->m_sOperation;
@@ -569,8 +562,7 @@ abstract class Controller extends AbstractController
$oKpi = new ExecutionKPI();
http_response_code($iResponseCode);
header('Content-Type: application/json');
foreach ($aHeaders as $sHeader)
{
foreach ($aHeaders as $sHeader) {
header($sHeader);
}
$sJSON = json_encode($aParams);
@@ -623,16 +615,13 @@ abstract class Controller extends AbstractController
$sArchiveFileFullPath = tempnam(SetupUtils::GetTmpDir(), 'itop_download-').'.zip';
$oArchive = new ZipArchive();
$oArchive->open($sArchiveFileFullPath, ZipArchive::CREATE);
foreach ($aFiles as $sFile)
{
foreach ($aFiles as $sFile) {
$oArchive->addFile($sFile, basename($sFile));
}
$oArchive->close();
if ($bUnlinkFiles)
{
foreach ($aFiles as $sFile)
{
if ($bUnlinkFiles) {
foreach ($aFiles as $sFile) {
unlink($sFile);
}
}
@@ -645,8 +634,7 @@ abstract class Controller extends AbstractController
$sFileMimeType = utils::GetFileMimeType($sFilePath);
header('Content-Type: '.$sFileMimeType);
if ($bFileTransfer)
{
if ($bFileTransfer) {
header('Content-Disposition: attachment; filename="'.$sDownloadArchiveName.'"');
}
@@ -662,8 +650,7 @@ abstract class Controller extends AbstractController
readfile($sFilePath);
if ($bRemoveFile)
{
if ($bRemoveFile) {
unlink($sFilePath);
}
exit(0);
@@ -675,6 +662,7 @@ abstract class Controller extends AbstractController
* @api
*
* @param string $sScript Script path to link
*
* @since 3.2.0 $sScript must be absolute URI
*/
public function AddLinkedScript($sScript)
@@ -688,6 +676,7 @@ abstract class Controller extends AbstractController
* @api
*
* @param string $sStylesheet Stylesheet path to link
*
* @since 3.2.0 $sScript must be absolute URI
*/
public function AddLinkedStylesheet($sStylesheet)
@@ -710,13 +699,13 @@ abstract class Controller extends AbstractController
/**
* Add an AJAX tab to the current page
*
* @param string $sCode Code of the tab
* @api
*
* @param string $sURL URL to call when the tab is activated
* @param bool $bCache If true, cache the result for the current web page
* @param string $sLabel Label of the tab (if null the code is translated)
*
* @api
*
* @param string $sCode Code of the tab
*/
public function AddAjaxTab($sCode, $sURL, $bCache = true, $sLabel = null)
{
@@ -728,6 +717,7 @@ abstract class Controller extends AbstractController
/**
* @param array $aBlockParams
*
* @since 3.0.0
*/
public function SetBlockParams(array $aBlockParams)
@@ -747,18 +737,20 @@ abstract class Controller extends AbstractController
}
/**
* @since 2.7.7 3.0.1 3.1.0 N°4760 method creation
* @see Controller::SetBreadCrumbEntry() to set breadcrumb content (by default will be title)
* @since 2.7.7 3.0.1 3.1.0 N°4760 method creation
*/
public function DisableBreadCrumb() {
public function DisableBreadCrumb()
{
$this->bIsBreadCrumbEnabled = false;
}
/**
* @since 2.7.7 3.0.1 3.1.0 N°4760 method creation
* @see iTopWebPage::SetBreadCrumbEntry()
* @since 2.7.7 3.0.1 3.1.0 N°4760 method creation
*/
public function SetBreadCrumbEntry($sId, $sLabel, $sDescription, $sUrl = '', $sIcon = '') {
public function SetBreadCrumbEntry($sId, $sLabel, $sDescription, $sUrl = '', $sIcon = '')
{
$this->aBreadCrumbEntry = [$sId, $sLabel, $sDescription, $sUrl, $sIcon];
}
@@ -779,7 +771,7 @@ abstract class Controller extends AbstractController
*/
public function GetFormBuilder(AbstractFormBlock $oFormBlock, mixed $data = null): FormBuilderInterface
{
return $this->oFormFactoryBuilder->getFormFactory()->createNamedBuilder($oFormBlock->GetName(), $oFormBlock->GetFormType(), $data,$oFormBlock->GetOptions());
return $this->oFormFactoryBuilder->getFormFactory()->createNamedBuilder($oFormBlock->GetName(), $oFormBlock->GetFormType(), $data, $oFormBlock->GetOptions());
}
/**
@@ -797,7 +789,8 @@ abstract class Controller extends AbstractController
if (is_null($data)) {
$data = $type::GetDefaultData();
}
return $this->GetFormBuilder($type, $data,$options)->getForm();
return $this->GetFormBuilder($type, $data, $options)->getForm();
}
/**
@@ -811,26 +804,25 @@ abstract class Controller extends AbstractController
private function RenderTemplate(array $aParams, string $sName, string $sTemplateFileExtension, string &$sErrorMsg = null): string|false
{
$sTemplateFile = $sName.'.'.$sTemplateFileExtension.'.twig';
if (empty($this->oTwig))
{
if (empty($this->oTwig)) {
throw new Exception('Not initialized. Call Controller::InitFromModule() or Controller::SetViewPath() before any display');
}
try
{
try {
return $this->oTwig->render($sTemplateFile, $aParams);
}
catch (SyntaxError $e) {
IssueLog::Error($e->getMessage().' - file: '.$e->getFile().'('.$e->getLine().')');
return $this->oTwig->render('application/forms/itop_error.html.twig', ['sControllerError' => $e->getMessage()]);
}
catch (Exception $e) {
$sExceptionMessage = $e->getMessage();
if (str_contains($sExceptionMessage, 'at line')) {
IssueLog::Error($sExceptionMessage);
return $this->oTwig->render('application/forms/itop_error.html.twig', ['sControllerError' => $sExceptionMessage]);
}
if (!str_contains($sExceptionMessage, 'Unable to find template'))
{
if (!str_contains($sExceptionMessage, 'Unable to find template')) {
IssueLog::Error($sExceptionMessage);
}
if (is_null($sErrorMsg)) {
@@ -849,8 +841,7 @@ abstract class Controller extends AbstractController
*/
private function CreatePage(string $sPageType): void
{
switch ($sPageType)
{
switch ($sPageType) {
case self::ENUM_PAGE_TYPE_HTML:
$this->oPage = new iTopWebPage($this->GetOperationTitle(), false);
$this->oPage->add_http_headers();
@@ -885,7 +876,7 @@ abstract class Controller extends AbstractController
}
$this->oTwig->addGlobal('UIBlockParent', [$this->oPage]);
$this->oTwig->addGlobal('oPage', $this->oPage);
$this->oTwig->addGlobal('debug', utils::IsDevelopmentEnvironment());
//$this->oTwig->addGlobal('debug', utils::IsDevelopmentEnvironment());
}
/**
@@ -959,11 +950,10 @@ abstract class Controller extends AbstractController
}
}
/**
* @param string $sKey
* @param $value
*
* @since 3.0.0
*/
private function SetBlockParamToPage(string $sKey, $value)

View File

@@ -33,11 +33,9 @@ use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
use ContextTag;
use DateTimeFormat;
use DBSearch;
use DeprecatedCallsLog;
use Dict;
use ExecutionKPI;
use InlineImage;
use iPageUIBlockExtension;
use MetaModel;
use UserRights;
use utils;
@@ -756,7 +754,7 @@ HTML;
}
}
// Render HTKL content
// Render HTML content
$sHtml = $this->RenderContent();
// Echo global HTML

View File

@@ -1,6 +1,8 @@
{# @copyright Copyright (C) 2010-2025 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
<div id="itop_profiler">
<turbo-frame id="itop_profiler_turbo_frame">
<div id="turbo_itop_profiler">
{{ sProfilerContent|raw }}
</div>
</div>
</turbo-frame>

View File

@@ -1,7 +1,7 @@
{# @copyright Copyright (C) 2010-2025 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
<turbo-stream action="update" target="itop_profiler">
<turbo-stream action="update" target="turbo_itop_profiler">
<template>
{{ sProfilerContent|raw }}
</template>