From bec5ff474979d37bcaa28fbcdd4ca518be72a184 Mon Sep 17 00:00:00 2001 From: MDW Date: Tue, 9 Apr 2024 23:21:28 +0200 Subject: [PATCH] Fix: Enforce/use int nature of BookKeeping(Line)::$piece_num, fix hooks typings (#29298) * Fix: Enforce/use int nature of BookKeeping(Line)::$piece_num * Fix typing in hookmanager class * Improve DolHooksCollector phpdoc * Fix PhanTypePossiblyInvalidDimOffset by testing index's existence * Ignore PhanTypePossiblyInvalidDimOffset that phan can not detect * Allow to be null, initialise instead of unset --- htdocs/accountancy/bookkeeping/card.php | 27 +++++----- .../accountancy/class/bookkeeping.class.php | 3 ++ htdocs/core/class/commonhookactions.class.php | 3 +- htdocs/core/class/hookmanager.class.php | 49 +++++++++++++------ .../modules/mrp/doc/pdf_vinci.modules.php | 2 +- .../class/DataCollector/DolHooksCollector.php | 8 +-- htdocs/index.php | 14 ++++-- .../template/class/actions_mymodule.class.php | 3 +- 8 files changed, 71 insertions(+), 38 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/card.php b/htdocs/accountancy/bookkeeping/card.php index d775e6ae61e..74ae94c98ff 100644 --- a/htdocs/accountancy/bookkeeping/card.php +++ b/htdocs/accountancy/bookkeeping/card.php @@ -4,6 +4,7 @@ * Copyright (C) 2013-2024 Alexandre Spangaro * Copyright (C) 2017 Laurent Destailleur * Copyright (C) 2018-2020 Frédéric France + * Copyright (C) 2024 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -227,7 +228,7 @@ if (empty($reshook)) { $object = new BookKeeping($db); $result = $object->fetch($id, null, $mode); - $piece_num = $object->piece_num; + $piece_num = (int) $object->piece_num; if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); @@ -284,7 +285,7 @@ if (empty($reshook)) { } $action = ''; $id = $object->id; - $piece_num = $object->piece_num; + $piece_num = (int) $object->piece_num; } } } @@ -438,7 +439,7 @@ if ($action == 'create') { $head = array(); $h = 0; - $head[$h][0] = $_SERVER['PHP_SELF'].'?piece_num='.$object->piece_num.($mode ? '&mode='.$mode : ''); + $head[$h][0] = $_SERVER['PHP_SELF'].'?piece_num='.((int) $object->piece_num).($mode ? '&mode='.$mode : ''); $head[$h][1] = $langs->trans("Transaction"); $head[$h][2] = 'transaction'; $h++; @@ -467,14 +468,14 @@ if ($action == 'create') { if ($action != 'editdate') { print ''; if ($permissiontoadd) { - print 'piece_num).'&mode='.urlencode((string) $mode).'">'.img_edit($langs->transnoentitiesnoconv('SetDate'), 1).''; + print 'piece_num).'&mode='.urlencode((string) $mode).'">'.img_edit($langs->transnoentitiesnoconv('SetDate'), 1).''; } print ''; } print ''; print ''; if ($action == 'editdate') { - print '
'; + print ''; if ($optioncss != '') { print ''; } @@ -498,14 +499,14 @@ if ($action == 'create') { if ($action != 'editjournal') { print ''; if ($permissiontoadd) { - print 'piece_num).'&mode='.urlencode((string) $mode).'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).''; + print 'piece_num).'&mode='.urlencode((string) $mode).'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).''; } print ''; } print ''; print ''; if ($action == 'editjournal') { - print ''; + print ''; if ($optioncss != '') { print ''; } @@ -529,14 +530,14 @@ if ($action == 'create') { if ($action != 'editdocref') { print ''; if ($permissiontoadd) { - print 'piece_num).'&mode='.urlencode((string) $mode).'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).''; + print 'piece_num).'&mode='.urlencode((string) $mode).'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).''; } print ''; } print ''; print ''; if ($action == 'editdocref') { - print ''; + print ''; if ($optioncss != '') { print ''; } @@ -664,7 +665,7 @@ if ($action == 'create') { // List of movements print load_fiche_titre($langs->trans("ListeMvts"), '', ''); - print ''; + print ''; if ($optioncss != '') { print ''; } @@ -787,7 +788,7 @@ if ($action == 'create') { print ''; if ($permissiontoadd) { if (empty($line->date_export) && empty($line->date_validation)) { - print 'id . '&piece_num=' . urlencode($line->piece_num) . '&mode=' . urlencode((string) $mode) . '&token=' . urlencode(newToken()) . '">'; + print 'id . '&piece_num=' . ((int) $line->piece_num) . '&mode=' . urlencode((string) $mode) . '&token=' . urlencode(newToken()) . '">'; print img_edit('', 0, 'class="marginrightonly"'); print '  '; } else { @@ -802,7 +803,7 @@ if ($action == 'create') { $actiontodelete = 'confirm_delete'; } - print ''; + print ''; print img_delete(); print ''; } else { @@ -830,7 +831,7 @@ if ($action == 'create') { print '
'; print '
'; if ($total_debit == $total_credit) { - print ''.$langs->trans("ValidTransaction").''; + print ''.$langs->trans("ValidTransaction").''; } else { print ''; } diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php index e38bcd94993..fd8b6696117 100644 --- a/htdocs/accountancy/class/bookkeeping.class.php +++ b/htdocs/accountancy/class/bookkeeping.class.php @@ -3151,6 +3151,9 @@ class BookKeepingLine extends CommonObjectLine public $import_key; public $code_journal; public $journal_label; + /** + * @var int accounting transaction id + */ public $piece_num; /** diff --git a/htdocs/core/class/commonhookactions.class.php b/htdocs/core/class/commonhookactions.class.php index d3282360fbb..a6fd27afe7c 100644 --- a/htdocs/core/class/commonhookactions.class.php +++ b/htdocs/core/class/commonhookactions.class.php @@ -1,5 +1,6 @@ + * Copyright (C) 2024 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +29,7 @@ abstract class CommonHookActions { /** - * @var string String of results. + * @var ?string String of results. */ public $resprints; diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php index a7a4b6e0900..e43e13610ab 100644 --- a/htdocs/core/class/hookmanager.class.php +++ b/htdocs/core/class/hookmanager.class.php @@ -2,6 +2,7 @@ /* Copyright (C) 2010-2016 Laurent Destailleur * Copyright (C) 2010-2014 Regis Houssin * Copyright (C) 2010-2011 Juanjo Menent + * Copyright (C) 2024 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,28 +45,41 @@ class HookManager */ public $errors = array(); - // Context hookmanager was created for ('thirdpartycard', 'thirdpartydao', ...) + /** + * @var string[] Context hookmanager was created for ('thirdpartycard', 'thirdpartydao', ...) + */ public $contextarray = array(); - // Array with instantiated classes + /** + * array> Array with instantiated classes + */ public $hooks = array(); /** - * @var array List of hooks called during this request + * @var array List of hooks called during this request (key = hash) */ public $hooksHistory = []; - // Array result + /** + * @var mixed[] Result + */ public $resArray = array(); - // Printable result + + /** + * @var string Printable result + */ public $resPrint = ''; - // Nb of qualified hook ran + + /** + * @var int Nb of qualified hook ran + */ public $resNbOfHooks = 0; /** * Constructor * * @param DoliDB $db Database handler + * @return void */ public function __construct($db) { @@ -82,7 +96,7 @@ class HookManager * Then when a hook executeHooks('aMethod'...) is called, the method aMethod found into class will be executed. * * @param string[] $arraycontext Array list of searched hooks tab/features. For example: 'thirdpartycard' (for hook methods into page card thirdparty), 'thirdpartydao' (for hook methods into Societe), ... - * @return int 0 or 1 + * @return int<0,1> 0 or 1 */ public function initHooks($arraycontext) { @@ -125,6 +139,7 @@ class HookManager if ($resaction) { $controlclassname = 'Actions'.ucfirst($module); $actionInstance = new $controlclassname($this->db); + '@phan-var-force CommonHookActions $actionInstance'; $priority = empty($actionInstance->priority) ? 50 : $actionInstance->priority; $this->hooks[$context][$priority.':'.$module] = $actionInstance; } @@ -150,10 +165,10 @@ class HookManager * Execute hooks (if they were initialized) for the given method * * @param string $method Name of method hooked ('doActions', 'printSearchForm', 'showInputField', ...) - * @param array $parameters Array of parameters - * @param Object $object Object to use hooks on + * @param array $parameters Array of parameters + * @param object $object Object to use hooks on * @param string $action Action code on calling page ('create', 'edit', 'view', 'add', 'update', 'delete'...) - * @return int For 'addreplace' hooks (doActions, formConfirm, formObjectOptions, pdf_xxx,...): Return 0 if we want to keep standard actions, >0 if we want to stop/replace standard actions, <0 if KO. Things to print are returned into ->resprints and set into ->resPrint. Things to return are returned into ->results by hook and set into ->resArray for caller. + * @return int<-1,1> For 'addreplace' hooks (doActions, formConfirm, formObjectOptions, pdf_xxx,...): Return 0 if we want to keep standard actions, >0 if we want to stop/replace standard actions, <0 if KO. Things to print are returned into ->resprints and set into ->resPrint. Things to return are returned into ->results by hook and set into ->resArray for caller. * For 'output' hooks (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...): Return 0 if we want to keep standard actions, >0 uf we want to stop/replace standard actions (at least one > 0 and replacement will be done), <0 if KO. Things to print are returned into ->resprints and set into ->resPrint. Things to return are returned into ->results by hook and set into ->resArray for caller. * All types can also return some values into an array ->results that will be merged into this->resArray for caller. * $this->error or this->errors are also defined by class called by this function if error. @@ -170,6 +185,7 @@ class HookManager 'contexts' => $this->contextarray, 'file' => $trace[0]['file'], 'line' => $trace[0]['line'], + 'count' => 0, ]; $hash = md5(json_encode($hookInformations)); if (!empty($this->hooksHistory[$hash])) { @@ -245,6 +261,7 @@ class HookManager $error = 0; foreach ($this->hooks as $context => $modules) { // $this->hooks is an array with context as key and value is an array of modules that handle this context if (!empty($modules)) { + '@phan-var-force array $modules'; // Loop on each active hooks of module for this context foreach ($modules as $module => $actionclassinstance) { $module = preg_replace('/^\d+:/', '', $module); @@ -278,6 +295,7 @@ class HookManager $parameters['currentcontext'] = $context; // Hooks that must return int (hooks with type 'addreplace') if ($hooktype == 'addreplace') { + // @phan-suppress-next-line PhanUndeclaredMethod The method's existence is tested above. $resactiontmp = $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example) $resaction += $resactiontmp; @@ -298,9 +316,9 @@ class HookManager if (!empty($actionclassinstance->resprints)) { if ($resactiontmp > 0) { - $localResPrint = $actionclassinstance->resprints; + $localResPrint = (string) $actionclassinstance->resprints; } else { - $localResPrint .= $actionclassinstance->resprints; + $localResPrint .= (string) $actionclassinstance->resprints; } } } else { @@ -315,6 +333,7 @@ class HookManager dol_syslog("Call method ".$method." of class ".get_class($actionclassinstance).", module=".$module.", hooktype=".$hooktype, LOG_DEBUG); } + // @phan-suppress-next-line PhanUndeclaredMethod The method's existence is tested above. $resactiontmp = $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example) $resaction += $resactiontmp; @@ -322,7 +341,7 @@ class HookManager $localResArray = array_merge_recursive($localResArray, $actionclassinstance->results); } if (!empty($actionclassinstance->resprints)) { - $localResPrint .= $actionclassinstance->resprints; + $localResPrint .= (string) $actionclassinstance->resprints; } if (is_numeric($resactiontmp) && $resactiontmp < 0) { $error++; @@ -342,8 +361,8 @@ class HookManager //print "After hook context=".$context." ".get_class($actionclassinstance)." method=".$method." hooktype=".$hooktype." results=".count($actionclassinstance->results)." resprints=".count($actionclassinstance->resprints)." resaction=".$resaction."
\n"; - unset($actionclassinstance->results); - unset($actionclassinstance->resprints); + $actionclassinstance->results = array(); + $actionclassinstance->resprints = null; } } } diff --git a/htdocs/core/modules/mrp/doc/pdf_vinci.modules.php b/htdocs/core/modules/mrp/doc/pdf_vinci.modules.php index ee0b0cf3ff9..70fdb1edb89 100644 --- a/htdocs/core/modules/mrp/doc/pdf_vinci.modules.php +++ b/htdocs/core/modules/mrp/doc/pdf_vinci.modules.php @@ -999,7 +999,7 @@ class pdf_vinci extends ModelePDFMo $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height); } - if (empty($hidetop)) { + if (empty($hidetop) && array_key_exists('title', $colDef) && array_key_exists('width', $colDef)) { $pdf->SetXY($colDef['xStartPos'] + $colDef['title']['padding'][3], $tab_top + $colDef['title']['padding'][0]); $textWidth = $colDef['width'] - $colDef['title']['padding'][3] - $colDef['title']['padding'][1]; diff --git a/htdocs/debugbar/class/DataCollector/DolHooksCollector.php b/htdocs/debugbar/class/DataCollector/DolHooksCollector.php index 52fb3a9ae38..09bba301c3f 100644 --- a/htdocs/debugbar/class/DataCollector/DolHooksCollector.php +++ b/htdocs/debugbar/class/DataCollector/DolHooksCollector.php @@ -1,5 +1,6 @@ + * Copyright (C) 2024 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,7 +24,6 @@ use DebugBar\DataCollector\RequestDataCollector; - /** * DolRequestDataCollector class */ @@ -32,7 +32,7 @@ class DolHooksCollector extends RequestDataCollector /** * Collects the data from the collectors * - * @return array Array of collected data + * @return array{nb_of_hooks:int,hooks:array} Array of collected data */ public function collect() { @@ -41,7 +41,7 @@ class DolHooksCollector extends RequestDataCollector */ global $hookmanager; - $data = ['hooks' => []]; + $data = ['hooks' => [], 'nb_of_hooks' => 0]; if (empty($hookmanager->hooksHistory)) { return $data; } @@ -62,7 +62,7 @@ class DolHooksCollector extends RequestDataCollector /** * Return widget settings * - * @return array Array + * @return array Array */ public function getWidgets() { diff --git a/htdocs/index.php b/htdocs/index.php index 1d44347356c..d6af48f77fb 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -5,6 +5,7 @@ * Copyright (C) 2011-2012 Juanjo Menent * Copyright (C) 2015 Marcos García * Copyright (C) 2021 Frédéric France + * Copyright (C) 2024 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,9 +44,15 @@ $hookmanager->initHooks(array('index')); */ $nbmodulesnotautoenabled = count($conf->modules); -if (in_array('fckeditor', $conf->modules)) $nbmodulesnotautoenabled--; -if (in_array('export', $conf->modules)) $nbmodulesnotautoenabled--; -if (in_array('import', $conf->modules)) $nbmodulesnotautoenabled--; +if (in_array('fckeditor', $conf->modules)) { + $nbmodulesnotautoenabled--; +} +if (in_array('export', $conf->modules)) { + $nbmodulesnotautoenabled--; +} +if (in_array('import', $conf->modules)) { + $nbmodulesnotautoenabled--; +} // Check if company name is defined (first install) if (!getDolGlobalString('MAIN_INFO_SOCIETE_NOM') || !getDolGlobalString('MAIN_INFO_SOCIETE_COUNTRY')) { @@ -522,6 +529,7 @@ if (!getDolGlobalString('MAIN_DISABLE_GLOBAL_WORKBOARD') && getDolGlobalInt('MAI if (!empty($groupElement['lang'])) { $langs->load($groupElement['lang']); } + // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset $groupName = $langs->trans($groupElement['groupName']); $groupKeyLowerCase = strtolower($groupKey); diff --git a/htdocs/modulebuilder/template/class/actions_mymodule.class.php b/htdocs/modulebuilder/template/class/actions_mymodule.class.php index 3b9d04b0e38..d76e193d30e 100644 --- a/htdocs/modulebuilder/template/class/actions_mymodule.class.php +++ b/htdocs/modulebuilder/template/class/actions_mymodule.class.php @@ -1,5 +1,6 @@ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -52,7 +53,7 @@ class ActionsMyModule extends CommonHookActions public $results = array(); /** - * @var string String displayed by executeHook() immediately after return + * @var ?string String displayed by executeHook() immediately after return */ public $resprints;