From 1e2dd2e16e09d63c3cc77c8cf73d56eca064018f Mon Sep 17 00:00:00 2001
From: "Hahn Axel (hahn)" <axel.hahn@unibe.ch>
Date: Wed, 28 Aug 2024 14:41:29 +0200
Subject: [PATCH] project class: php8 only; added variable types; short array
 syntax

---
 .../deployment/classes/project.class.php      | 726 ++++++++++--------
 1 file changed, 388 insertions(+), 338 deletions(-)

diff --git a/public_html/deployment/classes/project.class.php b/public_html/deployment/classes/project.class.php
index 7d2b7332..9c06d48b 100644
--- a/public_html/deployment/classes/project.class.php
+++ b/public_html/deployment/classes/project.class.php
@@ -25,6 +25,8 @@ require_once 'htmlguielements.class.php';
 
   ---------------------------------------------------------------------
   2013-11-08  Axel <axel.hahn@iml.unibe.ch>
+  (...)
+  2024-08-28  Axel   php8 only; added variable types; short array syntax
   ###################################################################### */
 
 /**
@@ -41,80 +43,84 @@ class project extends base
      * configuration ($aConfig in the config file)
      * @var array
      */
-    protected $_aConfig = array();
+    protected array $_aConfig = [];
 
     /**
      * configuration of the project (= $aProjects[ID] in the config file)
      * @var array
      */
-    protected $_aPrjConfig = array();
+    protected array $_aPrjConfig = [];
 
     /**
      * version infos of all phases
      * @var array
      */
-    protected $_aData = array();
+    protected array $_aData = [];
 
     /**
      * existing versions in the archive dir
      * @var array
      */
-    protected $_aVersions = array();
+    protected array $_aVersions = [];
 
     /**
      * output file to fetch processing content with ajax request
      * @var string
      */
-    protected $_sProcessTempOut = false;
+    protected string $_sProcessTempOut = '';
 
     /**
      * places of version infos in each deployment phase
      * @var array 
      */
-    protected $_aPlaces = array(
+    protected array $_aPlaces = [
         "onhold" => "Queue",
         "ready2install" => "Puppet",
         "deployed" => "Installiert",
-    );
+    ];
 
     /**
      * collector for returncodes of multiple exec calls
      * @var int
      */
-    protected $_iRcAll = 0;
+    protected int $_iRcAll = 0;
 
 
     /**
      * reference to html renderer class to draw output items
      * @var object
      */
-    protected $_oHtml = false;
+    protected object $_oHtml;
 
     /**
      * object to access a version control, .e. git
      * @var object
      */
-    protected $_oVcs = false;
+    protected object $_oVcs;
 
     /**
      * object for rollout
-     * @var type
+     * @var object
      */
-    public $oRolloutPlugin = false;
+    public object $oRolloutPlugin;
 
-    protected $_sBranchname = false;
+    /**
+     * Name of the current branch
+     * @var string
+     */
+    protected string $_sBranchname = '';
 
     /**
-     * send messages
-     * @var messengerobject
+     * messenger object to send messages
+     * @var object
      */
-    protected $oMessenger = false;
+    protected object $oMessenger;
 
     /**
      * collected errors
      * @var array
      */
-    protected $_errors = [];
+    protected array $_errors = [];
 
     // ----------------------------------------------------------------------
     // constructor
@@ -124,7 +130,7 @@ class project extends base
      * constructor
      * @param string $sId  id of the project
      */
-    public function __construct($sId = false)
+    public function __construct(string $sId = '')
     {
         $this->oUser = new user();
         $this->_oHtml = new htmlguielements();
@@ -144,7 +150,7 @@ class project extends base
      * @param  string $sLevel    warnlevel of the given message
      * @return bool
      */
-    protected function log($sMessage, $sLevel = "info")
+    protected function log(string $sMessage, string $sLevel = "info")
     {
         global $oCLog;
         return $oCLog->add(basename(__FILE__) . " class " . __CLASS__ . " - " . $sMessage, $sLevel);
@@ -157,26 +163,19 @@ class project extends base
      */
     protected function _sendMessage($sMessage)
     {
-        $aConfig = array();
+        $aConfig = [];
 
-        if (
-            array_key_exists('messenger', $this->_aPrjConfig)
-            && array_key_exists('slack', $this->_aPrjConfig['messenger'])
-        ) {
+        if (isset($this->_aPrjConfig['messenger']['slack'])) {
             $sSlack = $this->_aPrjConfig['messenger']['slack'];
-            $aConfig['slack'] = array('incomingurl' => $sSlack);
-            foreach (array('user', 'icon') as $sKey) {
+            $aConfig['slack'] = ['incomingurl' => $sSlack];
+            foreach (['user', 'icon'] as $sKey) {
                 if (isset($this->_aConfig['messenger']['slack']['presets'][$sSlack][$sKey])) {
                     $aConfig['slack'][$sKey] = $this->_aConfig['messenger']['slack']['presets'][$sSlack][$sKey];
                 }
             }
         }
 
-        if (
-            array_key_exists('messenger', $this->_aPrjConfig)
-            && array_key_exists('email', $this->_aPrjConfig['messenger'])
-            && $this->_aPrjConfig['messenger']['email']
-        ) {
+        if (isset($this->_aConfig['messenger']['email'])) {
             $aConfig['email'] = $this->_aConfig['messenger']['email'];
             $aConfig['email']['to'] = $this->_aPrjConfig['messenger']['email'];
         }
@@ -185,7 +184,7 @@ class project extends base
         }
 
         // init on first usage
-        if (!$this->oMessenger) {
+        if (!isset($this->oMessenger) || !$this->oMessenger) {
             $this->oMessenger = new messenger($aConfig);
         }
 
@@ -193,7 +192,7 @@ class project extends base
         $sText = $this->getLabel() . ': ' . html_entity_decode($sMessage) . "\n"
             . t('page-login-username') . ": " . $this->oUser->getUsername() . "\n";
         if (isset($_SERVER) && is_array($_SERVER)) {
-            if (array_key_exists('HTTP_HOST', $_SERVER)) {
+            if (isset($_SERVER['HTTP_HOST'])) {
                 $sText .= t('project-home') . ': ' . $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . '/deployment/' . $this->getId() . "\n";
             }
             /*
@@ -202,13 +201,14 @@ class project extends base
         }
              */
         }
-        return $this->oMessenger->sendMessage($sText);
+        $this->oMessenger->sendMessage($sText);
+        return true;
     }
     /**
      * read default config file
      * @return boolean
      */
-    protected function _readConfig()
+    protected function _readConfig(): bool
     {
         global $aConfig;
         $this->_aConfig = $aConfig;
@@ -219,14 +219,14 @@ class project extends base
      * validate config data
      * @return boolean
      */
-    protected function _verifyConfig()
+    protected function _verifyConfig(): bool
     {
         if (!is_array($this->_aPrjConfig) || !count($this->_aPrjConfig)) {
             // die(t("class-project-error-no-config"));
             throw new Exception(t("class-project-error-no-config"));
         }
 
-        if (!array_key_exists("packageDir", $this->_aConfig)) {
+        if (!isset($this->_aConfig["packageDir"])) {
             die(t("class-project-error-no-packagedir"));
         }
         if (!$this->_aConfig["packageDir"]) {
@@ -235,7 +235,7 @@ class project extends base
         if (!file_exists($this->_aConfig["packageDir"])) {
             die(sprintf(t("class-project-error-packagedir-does-not-exist"), $this->_aConfig['packageDir']));
         }
-        if (!array_key_exists("archiveDir", $this->_aConfig)) {
+        if (!isset($this->_aConfig["archiveDir"])) {
             die(t("class-project-error-no-archivedir"));
         }
         if (!$this->_aConfig["archiveDir"]) {
@@ -245,8 +245,8 @@ class project extends base
             die(sprintf(t("class-project-error-packagedir-does-not-exist"), $this->_aConfig['archiveDir']));
         }
 
-        foreach (array("fileprefix", "build", "phases") as $sKey) {
-            if (!array_key_exists($sKey, $this->_aPrjConfig)) {
+        foreach (["fileprefix", "build", "phases"] as $sKey) {
+            if (!isset($this->_aPrjConfig[$sKey])) {
                 die(sprintf(t("class-project-error-missing-prjkey"), $sKey, print_r($this->_aPrjConfig, true)));
             }
         }
@@ -260,7 +260,7 @@ class project extends base
           die(sprintf(t("class-project-error-data-does-not-exist"), $this->_aConfig['dataDir']));
           }
 
-          foreach (array("database", "projects", "sshkeys") as $sKey) {
+          foreach (["database", "projects", "sshkeys"] as $sKey) {
           $sTestDir=$this->_aConfig["dataDir"]."/$sKey";
           if (!file_exists($sTestDir)) {
           mkdir($sTestDir);
@@ -273,10 +273,11 @@ class project extends base
 
     /**
      * execute a commandline; returns a string of output of timestamp, command, output and returncode
-     * @param string $sCommand
+     * @param string $sCommand  command to execute
+     * @param bool   $bFlush    flush content of output buffer
      * @return string
      */
-    protected function _execAndSend($sCommand, $bFlush = false)
+    protected function _execAndSend(string $sCommand, bool $bFlush = false): string
     {
         $this->log(__FUNCTION__ . " start");
         $sReturn = '';
@@ -298,15 +299,15 @@ class project extends base
         $this->log(__FUNCTION__ . " ended command $sCommand");
         $sReturn .= (count($aOutput)) ? htmlentities(implode("\n", $aOutput)) . "\n" : "";
         /*
-          $descriptorspec = array(
-          0 => array("pipe", "r"), // stdin is a pipe that the child will read from
-          1 => array("pipe", "w"), // stdout is a pipe that the child will write to
-          2 => array("pipe", "w")    // stderr is a pipe that the child will write to
-          );
+          $descriptorspec = [
+          0 => ["pipe", "r"], // stdin is a pipe that the child will read from
+          1 => ["pipe", "w"], // stdout is a pipe that the child will write to
+          2 => ["pipe", "w"]    // stderr is a pipe that the child will write to
+          ];
           if ($bFlush) {
           flush();
           }
-          $process = proc_open($sCommand, $descriptorspec, $pipes, realpath('./'), array());
+          $process = proc_open($sCommand, $descriptorspec, $pipes, realpath('./'), []);
 
 
           $sErrors = false;
@@ -353,12 +354,13 @@ class project extends base
     }
 
     /**
-     * add an action log message
-     * @param string $sMessage    message
-     * @param string $sAction     project action
-     * @param string $sLoglevel   loglevel
+     * add an action log message for the current project
+     * @param string $sMessage    message text
+     * @param string $sAction     project action i.e. build, deploy, ...
+     * @param string $sLoglevel   loglevel; default: info
+     * @return void
      */
-    protected function _logaction($sMessage, $sAction = "", $sLoglevel = "info")
+    protected function _logaction(string $sMessage, string $sAction = "", string $sLoglevel = "info"): void
     {
         require_once("actionlog.class.php");
         $oLog = new Actionlog($this->_aConfig["id"]);
@@ -369,7 +371,12 @@ class project extends base
     // GETTER
     // ----------------------------------------------------------------------
 
-    protected function _getConfigFile($sId)
+    /**
+     * Get filename of fonfigfile for this project
+     * @param string $sId  project id
+     * @return string
+     */
+    protected function _getConfigFile(string $sId): string
     {
         if (!$sId) {
             die(t("class-project-error-_getConfigFile-requires-id"));
@@ -378,49 +385,53 @@ class project extends base
     }
 
     /**
-     * get a full ath for temp directory (for a build)
+     * Get a full ath for temp directory (for a build)
      * @return string
      */
-    protected function _getTempDir()
+    protected function _getTempDir(): string
     {
         return $s = $this->_getBuildDir() . '/' . $this->_aPrjConfig["fileprefix"] . "_" . date("Ymd-His");
     }
 
     /**
-     * get full path where the project builds are (a build setes a subdir)
+     * Get full path where the project builds are (a build setes a subdir)
      * @return string
      */
-    protected function _getBuildDir()
+    protected function _getBuildDir(): string
     {
         return $this->_aConfig['buildDir'] . '/' . $this->_aConfig["id"];
     }
 
     /**
-     * get full path where the project default files are
-     * @return type
+     * Get full path where the project default files are
+     * This is an optional step in build() - you can sync default files into 
+     * the build directory. It returns false if the directory with default 
+     * files doesn't exist.
+     * 
+     * @return string|bool
      */
-    protected function _getDefaultsDir()
+    protected function _getDefaultsDir(): string|bool
     {
         $s = $this->_aConfig['buildDefaultsDir'] . '/' . $this->_aConfig["id"];
         return file_exists($s) ? $s : false;
     }
 
     /**
-     * get directory for infofile and package (without extension)
+     * Get directory for infofile and package (without extension)
+     * 
      * @param string $sPhase  one of preview|stage|live ...
      * @param string $sPlace  one of onhold|ready2install|deployed
      * @return string
      */
-    protected function _getFileBase($sPhase, $sPlace)
+    protected function _getFileBase(string $sPhase, string $sPlace): string
     {
-        if (!array_key_exists($sPhase, $this->_aConfig["phases"])) {
+        if (!isset($this->_aConfig["phases"][$sPhase])) {
             die(sprintf(t("class-project-error-wrong-phase"), $sPhase));
         }
-        if (!array_key_exists($sPlace, $this->_aPlaces)) {
+        if (!isset($this->_aPlaces[$sPlace])) {
             die(sprintf(t("class-project-error-wrong-place"), $sPlace));
         }
 
-
         // local file for onhold|ready2install
         $sBase = $this->_aConfig['packageDir'] . "/" . $sPhase . "/" . $this->_aPrjConfig["fileprefix"];
         if (!file_exists($this->_aConfig['packageDir'] . "/" . $sPhase)) {
@@ -433,7 +444,7 @@ class project extends base
         // $sBase .= "/" . $this->_aPrjConfig["fileprefix"];
         // url for deployed
         if ($sPlace == "deployed") {
-            if ($this->isActivePhase($sPhase) && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) {
+            if ($this->isActivePhase($sPhase) && isset($this->_aPrjConfig["phases"][$sPhase]["url"])) {
                 // $sBase = $this->_aPrjConfig["phases"][$sPhase]["url"] . $this->_aPrjConfig["fileprefix"];
                 $sBase = $this->_aPrjConfig["phases"][$sPhase]["url"];
             } else {
@@ -446,48 +457,53 @@ class project extends base
     }
 
     /**
-     * get filename for info/ meta file (.json file)
+     * Get filename for info/ meta file (.json file).
+     * It returns false if the base directory doesn't exist
+     * 
      * @param string $sPhase  one of preview|stage|live ...
      * @param string $sPlace  one of onhold|ready2install|deployed
      * @return string
      */
-    protected function _getInfofile($sPhase, $sPlace)
+    protected function _getInfofile(string $sPhase, string $sPlace): string|bool
     {
         $sBase = $this->_getFileBase($sPhase, $sPlace);
         return $sBase ? $sBase . '/' . $this->_aPrjConfig["fileprefix"] . '.json' : false;
     }
 
     /**
-     * get filename for package file (without file extension)
+     * Get filename for package file (without file extension)
+     * It returns false if the base directory doesn't exist
+     * 
      * @param string $sPhase  one of preview|stage|live ...
      * @param string $sPlace  one of onhold|ready2install|deployed
      * @return string
      */
-    protected function _getPackagefile($sPhase, $sPlace)
+    protected function _getPackagefile(string $sPhase, string $sPlace)
     {
         $sBase = $this->_getFileBase($sPhase, $sPlace);
         return $sBase ? $sBase . '/' . $this->_aPrjConfig["fileprefix"] : false;
     }
 
     /**
-     * list of files of a given phase and place
-     * @param string $sPhase  one of preview|stage|live ...
-     * @param string $sPlace  one of onhold|ready2install|deployed
-     * @return array
+     * Get a list of files of a given phase and place.
+     * It returns false if the base directory doesn't exist
+     * 
+     * @param string $sBase  base directory from where to get files (archive dir of a build)
+     * @return bool|array
      */
-    public function _getBuildfilesByDir($sBase)
+    public function _getBuildfilesByDir(string $sBase): bool|array
     {
-        $aReturn = array();
+        $aReturn = [];
         if (!$sBase || !is_dir($sBase)) {
             return false;
         }
         $iTotalSize = 0;
-        $aReturn = array(
+        $aReturn = [
             'dir' => $sBase,
             'filecount' => false,
             'totalsize' => false,
             'totalsize-hr' => false,
-        );
+        ];
 
         foreach (glob($sBase . '/*') as $sFile) {
             $sFileBase = basename($sFile);
@@ -513,12 +529,12 @@ class project extends base
                     break;
             }
             $iTotalSize += $aStat['size'];
-            $aReturn['files'][$sFileBase] = array(
+            $aReturn['files'][$sFileBase] = [
                 'type' => $sType,
                 'icon' => $this->_oHtml->getIcon($sIcon),
                 'extension' => $sExt,
                 'size' => $aStat['size'],
-            );
+            ];
             $aReturn['types'][$sType][] = $sFileBase;
         }
         $aReturn['totalsize'] = $iTotalSize;
@@ -529,51 +545,61 @@ class project extends base
     }
 
     /**
-     * list of files of a given phase and place
+     * Get a list of files of a given phase and place;
+     * It returns false if the base directory for phase + base doesn't exist
+     * 
      * @param string $sPhase  one of preview|stage|live ...
      * @param string $sPlace  one of onhold|ready2install|deployed
-     * @return array
+     * @return bool|array
      */
-    public function getBuildfilesByPlace($sPhase, $sPlace)
+    public function getBuildfilesByPlace(string $sPhase, string $sPlace): bool|array
     {
         $sBase = $this->_getFileBase($sPhase, $sPlace);
         return $this->_getBuildfilesByDir($sBase);
     }
 
     /**
-     * list of files of a given version number
+     * Get a list of files of a given version number
+     * It returns false if the version directory doesn't exist
+     * 
      * @param string $sVersion  name of version 
      * @return array
      */
-    public function getBuildfilesByVersion($sVersion)
+    public function getBuildfilesByVersion(string $sVersion): bool|array
     {
         return $this->_getBuildfilesByDir($this->_getProjectArchiveDir() . '/' . $sVersion);
     }
 
     /**
-     * get the group id of the project
-     * @return string
+     * Get the group id of the project
+     * It returns false if the group wasn't set
+     * 
+     * @return bool|string
      */
-    public function getProjectGroup()
+    public function getProjectGroup(): bool|string
     {
         return isset($this->_aPrjConfig["projectgroup"]) && $this->_aPrjConfig["projectgroup"] != '-1' ? $this->_aPrjConfig["projectgroup"] : false;
     }
+
     /**
-     * get the group label of the project
-     * @return string
+     * Get the group label (description) of the project
+     * It returns false if the group wasn't set
+     * 
+     * @return bool|string
      */
-    public function getProjectGroupLabel()
+    public function getProjectGroupLabel(): bool|string
     {
         $sGroupid = $this->getProjectGroup();
         return isset($this->_aConfig["projectgroups"][$sGroupid]) ? $this->_aConfig["projectgroups"][$sGroupid] : false;
     }
 
     /**
-     * get full path of a packed project archive
+     * Get full path of a packed project archive
+     * 
      * @param string $sVersion  version number of the build
      * @return string
      */
-    protected function _getArchiveDir($sVersion)
+    protected function _getArchiveDir(string $sVersion): string
     {
         if (!$sVersion) {
             die(t("class-project-error-_getArchiveDir-requires-id"));
@@ -586,10 +612,11 @@ class project extends base
      * - key "ok" anddata
      * or 
      * - key "error" with the message
-     * @param type $sTimestamp
+     * 
+     * @param string $sTimestamp
      * @return array
      */
-    protected function _getArchiveInfos($sTimestamp)
+    protected function _getArchiveInfos(string $sTimestamp): array
     {
         if (!$sTimestamp) {
             die(t("class-project-error-_getArchiveInfos-requires-id"));
@@ -603,7 +630,7 @@ class project extends base
             return $aReturn;
         }
         $aJson = json_decode(file_get_contents($sInfoFile), true);
-        if (is_array($aJson) && array_key_exists("version", $aJson)) {
+        if (is_array($aJson) && isset($aJson["version"])) {
             $aReturn = array_merge($aReturn, $aJson);
             $aReturn['ok'] = 1;
             /*
@@ -621,48 +648,26 @@ class project extends base
     }
 
     /**
-     * get the directory for archive files of this project
+     * Get the directory for archive files of this project
+     * 
      * @return string
      */
-    public function _getProjectArchiveDir()
+    public function _getProjectArchiveDir(): string
     {
         return $this->_aConfig["archiveDir"] . '/' . $this->_aConfig["id"];
     }
 
     /**
-     * TODO: REMOVE
-     * make an http get request and return the response body
-     * @param string $url
-     * @return string
-     */
-    private function _httpGet($url, $iTimeout = 5)
-    {
-        $this->log(__FUNCTION__ . " start");
-        if (!function_exists("curl_init")) {
-            die("ERROR: PHP CURL module is not installed.");
-        }
-        $this->log(__FUNCTION__ . " url: $url");
-        $ch = curl_init($url);
-        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
-        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
-        curl_setopt($ch, CURLOPT_TIMEOUT, $iTimeout);
-        curl_setopt($ch, CURLOPT_USERAGENT, 'IML Deployment GUI');
-        $res = curl_exec($ch);
-        curl_close($ch);
-        $this->log(__FUNCTION__ . " done url: $url");
-        return $res;
-    }
-
-    /**
-     * get all existing versions in archive and its usage
+     * Get all existing versions in archive and its usage
      * versions are array keys; where they are used is written in values
+     * 
      * @return array
      */
-    public function getVersions()
+    public function getVersions(): array
     {
 
         // --- read all file entries
-        $aReturn = array();
+        $aReturn = [];
         $sDir = $this->_getProjectArchiveDir();
         if (is_dir($sDir)) {
             foreach (scandir($sDir) as $sEntry) {
@@ -677,21 +682,23 @@ class project extends base
         foreach ($this->_aData["phases"] as $sPhase => $aData) {
             foreach (array_keys($this->_aPlaces) as $sPlace) {
                 if (isset($aData[$sPlace]["version"])) {
-                    $this->_aVersions[$aData[$sPlace]["version"]][] = array('phase' => $sPhase, 'place' => $sPlace);
+                    $this->_aVersions[$aData[$sPlace]["version"]][] = ['phase' => $sPhase, 'place' => $sPlace];
                 }
             }
         }
         ksort($this->_aVersions);
         return $this->_aVersions;
     }
+
     /**
-     * get an array with all existing build error output files (html)
+     * Get an array with all existing build error output files (html)
+     * 
      * @return array
      */
-    public function getBuildErrors($sProject = false)
+    public function getBuildErrors(string $sProject = ''): array
     {
         // --- read all file entries
-        $aReturn = array();
+        $aReturn = [];
         if (!$sProject) {
             $sProject = $this->_aPrjConfig["fileprefix"] . '_*';
         }
@@ -700,11 +707,14 @@ class project extends base
         }
         return $aReturn;
     }
+
     /**
-     * get an array with all existing build error output files (html)
-     * @return array
+     * Get an array with all existing build error output files (html)
+     * It returns false when path of given logfile contains ".." or the logfile doesn't exist.
+     * 
+     * @return bool|string
      */
-    public function getBuildErrorContent($sLogfile)
+    public function getBuildErrorContent($sLogfile): bool|string
     {
         if (!strpos('..', $sLogfile) === false) {
             return false;
@@ -717,16 +727,17 @@ class project extends base
     }
 
     /**
-     * get Array of all versions, metainfos, in which phases they are in use 
+     * Get an array of all versions, metainfos, in which phases they are in use 
      * and a rollback ist possible or not
+     * 
      * return array
      */
-    protected function _getVersionUsage()
+    protected function _getVersionUsage(): array
     {
-        $aVersionData = array();
+        $aVersionData = [];
         $sLastVersion = false;
         if (!count($this->getVersions())) {
-            return array();
+            return [];
         }
 
         foreach ($this->getVersions() as $sVersion => $aData) {
@@ -755,7 +766,7 @@ class project extends base
                             $bCanRollback = false;
                         }
                         /*
-                          if (!array_key_exists("ok", $aVersionData[$sVersion]["info"])){
+                          if (!isset($aVersionData[$sVersion]["info"]["ok"])){
                           $bCanRollback = false;
                           }
                          */
@@ -769,11 +780,12 @@ class project extends base
     }
 
     /**
-     * recursive delete 
+     * Recursive delete of a given directory
+     * 
      * @param string $dir  directory to delete
-     * @return type
+     * @return bool
      */
-    protected function _rmdir($dir)
+    protected function _rmdir(string $dir): bool
     {
         foreach (scandir($dir) as $sEntry) {
             if (is_dir($dir . '/' . $sEntry) && $sEntry != '.' && $sEntry != '..') {
@@ -785,17 +797,21 @@ class project extends base
     }
 
     /**
-     * cleanup of archive directory; it returns the list of deleted
-     * directories as array
-     * @return array
+     * Cleanup of archive directory; it returns the list of deleted
+     * directories as array.
+     * It returns a string with the error message in case of missing permission
+     * Otherwise it returns an array with all deleted directories.
+     * 
+     * @param bool $bDeleteAll  flag to delete all; default: false = it keeps a few versions
+     * @return string|array
      */
-    public function cleanupArchive($bDeleteAll = false)
+    public function cleanupArchive(bool $bDeleteAll = false): string|array
     {
         if (!$this->oUser->hasPermission("project-action-cleanup")) {
             return $this->oUser->showDenied();
         }
-        $aDelete = array();
-        $aUnused = array();
+        $aDelete = [];
+        $aUnused = [];
 
         $sDir = $this->_getProjectArchiveDir();
         $this->getVersions();
@@ -837,19 +853,21 @@ class project extends base
     }
 
     /**
-     * cleanup of archive directory; it returns the list of deleted
-     * directories as array
-     * @return array
+     * Cleanup of kept build directories (builds with errors) except the last N builds; 
+     * It returns a string with the error message in case of missing permission
+     * Otherwise it returns an array with all deleted directories.
+     * 
+     * @return string|array
      */
-    public function cleanupBuilds()
+    public function cleanupBuilds(): string|array
     {
         $this->log(__FUNCTION__ . " start");
         if (!$this->oUser->hasPermission("project-action-cleanup")) {
             return $this->oUser->showDenied();
         }
         $sDir = $this->_getBuildDir();
-        $aDirlist = array();
-        $aDelete = array();
+        $aDirlist = [];
+        $aDelete = [];
         if (is_dir($sDir)) {
             foreach (scandir($sDir) as $sEntry) {
                 if (is_dir($sDir . '/' . $sEntry) && $sEntry != '.' && $sEntry != '..')
@@ -864,7 +882,7 @@ class project extends base
             if ($this->_rmdir($sDir2)) {
                 $aDelete[] = $sDir2;
             } else {
-                echo t("class-project-warning-cannot-delete-build-dir", $sDir2);
+                echo sprintf(t("class-project-warning-cannot-delete-build-dir"), $sDir2);
             }
             ;
         }
@@ -873,83 +891,93 @@ class project extends base
     }
 
     /**
-     * cleanup cache of vcs
-     * @param type $iAge
+     * Cleanup cache of vcs
+     * It returns a string with error message in case of missing permission
+     * Otherwise it returns the success as true or false
+     * 
+     * @param int $iAge  max age in sec
+     * @return string|bool
      */
-    public function cleanupVcsCache($iAge = 0)
+    public function cleanupVcsCache($iAge = 0): string|bool
     {
         $this->log(__FUNCTION__ . " start");
         if (!$this->oUser->hasPermission("project-action-cleanup")) {
             return $this->oUser->showDenied();
         }
         $this->_initVcs();
-        if ($this->_oVcs) {
+        if (isset($this->_oVcs) && $this->_oVcs) {
             if (!method_exists($this->_oVcs, "cleanupCache")) {
                 // the version control class does not have this method
                 $this->log(__FUNCTION__ . " sorry, Method cleanupCache does not exist in this VCS class.");
-                return '';
+                return false;
             }
             return $this->_oVcs->cleanupCache($iAge);
         }
+        return false;
     }
 
     /**
-     * get conmplete config of the project
+     * Get conmplete config of the project
+     * 
      * @return array
      */
-    public function getConfig()
+    public function getConfig(): array
     {
         return $this->_aPrjConfig;
     }
 
     /**
-     * get name/ label of the project
+     * Get name/ label of the project
+     * 
      * @return string
      */
-    public function getLabel()
+    public function getLabel(): string
     {
         return isset($this->_aPrjConfig["label"]) ? $this->_aPrjConfig["label"] : '';
     }
 
     /**
-     * get description of the project
+     * Get description of the project
+     * 
      * @return string
      */
-    public function getDescription()
+    public function getDescription(): string
     {
         return isset($this->_aPrjConfig["description"]) ? $this->_aPrjConfig["description"] : '';
     }
 
     /**
-     * get the id of the current project
+     * Get the id of the current project
      * @return string
      */
-    public function getId()
+    public function getId(): string
     {
         return isset($this->_aConfig["id"]) ? $this->_aConfig["id"] : '';
     }
+
     /**
-     * get deploy and queue infos for all phases
+     * Get deploy and queue infos for all phases
      * It build up a subkey "progress" with info if a build is queued
      * or an installation of a new package is going on
+     * 
      * @return array
      */
-    public function getAllPhaseInfos()
+    public function getAllPhaseInfos(): array
     {
 
         $bHasQueue = false;
         $bHasDifferentVersions = false;
         $bFirstVersion = false;
 
-        if (!array_key_exists("phases", $this->_aData)) {
-            $this->_aData["phases"] = array();
+        if (!isset($this->_aData["phases"])) {
+            $this->_aData["phases"] = [];
         }
-        if (!array_key_exists("progress", $this->_aData)) {
-            $this->_aData["progress"] = array();
+        if (!isset($this->_aData["progress"])) {
+            $this->_aData["progress"] = [];
         }
 
         foreach (array_keys($this->_aConfig["phases"]) as $sPhase) {
-            if (!array_key_exists($sPhase, $this->_aData["phases"])) {
+            if (!isset($this->_aData["phases"][$sPhase])) {
                 $this->getPhaseInfos($sPhase);
             }
             // detect progress
@@ -972,39 +1000,40 @@ class project extends base
                 $bHasQueue = true;
             }
         }
-        $this->_aData["progress"] = array(
+        $this->_aData["progress"] = [
             'inprogress' => $bHasDifferentVersions,
             'hasQueue' => $bHasQueue,
-        );
+        ];
         return $this->_aData["phases"];
     }
 
     /**
-     * get statusinfos of a named phase
+     * Get statusinfos of a named phase
+     * 
      * @param string $sPhase name of the phase; one of preview|stage|live
      * @return array
      */
-    public function getPhaseInfos($sPhase)
+    public function getPhaseInfos(string $sPhase): array
     {
         if (!$sPhase) {
             die(t("class-project-error-getPhaseInfos-requires-phase"));
         }
-        if (!array_key_exists("phases", $this->_aData))
-            $this->_aData["phases"] = array();
+        if (!isset($this->_aData["phases"]))
+            $this->_aData["phases"] = [];
 
-        if (!array_key_exists($sPhase, $this->_aData["phases"])) {
+        if (!isset($this->_aData["phases"][$sPhase])) {
             if ($this->isActivePhase($sPhase)) {
 
-                $this->_aData["phases"][$sPhase] = array();
-                $aTmp = array();
+                $this->_aData["phases"][$sPhase] = [];
+                $aTmp = [];
 
                 // a blocked package is waiting for deployment timeslot?
                 $sKey = "onhold";
                 $sJsonfile = $this->_getInfofile($sPhase, $sKey);
-                $aTmp[$sKey] = array();
+                $aTmp[$sKey] = [];
                 if (file_exists($sJsonfile)) {
                     $aJson = json_decode(file_get_contents($sJsonfile), true);
-                    if (array_key_exists("version", $aJson)) {
+                    if (isset($aJson["version"])) {
                         $aTmp[$sKey] = $aJson;
                         $aTmp[$sKey]["infofile"] = $sJsonfile;
                         $aTmp[$sKey]["ok"] = 1;
@@ -1019,12 +1048,12 @@ class project extends base
                 // package for puppet
                 $sKey = "ready2install";
                 $sJsonfile = $this->_getInfofile($sPhase, $sKey);
-                $aTmp[$sKey] = array();
+                $aTmp[$sKey] = [];
                 if (file_exists($sJsonfile)) {
                     // $sPkgfile = $this->_getPackagefile($sPhase, $sKey);
                     // if (file_exists($sPkgfile)) {
                     $aJson = json_decode(file_get_contents($sJsonfile), true);
-                    if (is_array($aJson) && array_key_exists("version", $aJson)) {
+                    if (isset($aJson["version"])) {
                         $aTmp[$sKey] = $aJson;
                         $aTmp[$sKey]["infofile"] = $sJsonfile;
                         // $aTmp[$sKey]["packagefile"] = $sPkgfile;
@@ -1042,7 +1071,7 @@ class project extends base
                 // published data
                 $sKey = "deployed";
                 $sJsonfile = $this->_getInfofile($sPhase, $sKey);
-                $aTmp[$sKey] = array();
+                $aTmp[$sKey] = [];
 
                 // use version cache
                 require_once(__DIR__ . '/../../valuestore/classes/valuestore.class.php');
@@ -1052,11 +1081,11 @@ class project extends base
                 // echo "Place: <pre>" . print_r($oVersion->whereiam(), 1) . "</pre>";
                 // echo "Versionen: <pre>" . print_r($aVersions, 1) . "</pre>";
                 if (count($aVersions)) {
-                    $aTmp[$sKey] = array();
+                    $aTmp[$sKey] = [];
                     $aTmp[$sKey] = $aVersions[0]['_data'];
                     $aTmp[$sKey]["infofile"] = '[versioncache]';
 
-                    $aTmp[$sKey]['_hosts'] = array();
+                    $aTmp[$sKey]['_hosts'] = [];
                     foreach ($aVersions as $sHostname => $aHostdata) {
                         $aTmp[$sKey]['_hosts'][$aHostdata['host']] = $aHostdata;
                     }
@@ -1100,12 +1129,13 @@ class project extends base
      * </code>
      * returns<br>
      * Array ( [0] => project1 [1] => project2 ) 
+     * 
      * @param string $sort sort by "id" (default) or "label"
      * @return array
      */
-    public function getProjects($sort = 'id')
+    public function getProjects(string $sort = 'id'): array
     {
-        $aReturn = array();
+        $aReturn = [];
         foreach (glob(dirname($this->_getConfigFile("dummy")) . "/*.json") as $filename) {
             $aReturn[] = str_replace(".json", "", basename($filename));
         }
@@ -1129,8 +1159,9 @@ class project extends base
     }
 
     /**
-     * check if the given phase is active for this project
-     * @param string $sPhase
+     * Check if the given phase is active for this project
+     * 
+     * @param string $sPhase name of the phase; one of preview|stage|live
      * @return bool
      */
     public function isActivePhase(string $sPhase): bool
@@ -1182,7 +1213,7 @@ class project extends base
     public function getNextPhase(string $sPhase = ''): string
     {
         if ($sPhase) {
-            if (!array_key_exists($sPhase, $this->_aConfig["phases"])) {
+            if (!isset($this->_aConfig["phases"][$sPhase])) {
                 die(sprintf(t("class-project-error-wrong-phase"), $sPhase));
             }
         }
@@ -1237,7 +1268,7 @@ class project extends base
             // for better performance: skip check on overview page
             /*
               $aRepodata = $this->getRepoRevision();
-              if (!array_key_exists("revision", $aRepodata)) {
+              if (!isset($aRepodata["revision"])) {
               return false;
               }
              */
@@ -1246,7 +1277,7 @@ class project extends base
         }
 
 
-        if (!array_key_exists($sPhase, $this->_aConfig["phases"])) {
+        if (!isset($this->_aConfig["phases"][$sPhase])) {
             die(sprintf(t("class-project-error-wrong-phase"), $sPhase));
         }
         if (!$this->isActivePhase($sPhase)) {
@@ -1264,7 +1295,14 @@ class project extends base
         // array key "ok" must be in the ready2install and deployed info
         // and a version must be installed
         if (
-            array_key_exists($sPhase, $this->_aData["phases"]) && array_key_exists("onhold", $this->_aData["phases"][$sPhase]) && array_key_exists("ready2install", $this->_aData["phases"][$sPhase]) && array_key_exists("deployed", $this->_aData["phases"][$sPhase]) && array_key_exists("ok", $this->_aData["phases"][$sPhase]["onhold"]) && array_key_exists("ok", $this->_aData["phases"][$sPhase]["ready2install"]) && array_key_exists("ok", $this->_aData["phases"][$sPhase]["deployed"]) && array_key_exists("version", $this->_aData["phases"][$sPhase]["deployed"])
+            isset($this->_aData["phases"][$sPhase])
+            && isset($this->_aData["phases"][$sPhase]["onhold"])
+            && isset($this->_aData["phases"][$sPhase]["ready2install"])
+            && isset($this->_aData["phases"][$sPhase]["deployed"])
+            && isset($this->_aData["phases"][$sPhase]["onhold"]["ok"])
+            && isset($this->_aData["phases"][$sPhase]["ready2install"]["ok"])
+            && isset($this->_aData["phases"][$sPhase]["deployed"]["ok"])
+            && isset($this->_aData["phases"][$sPhase]["deployed"]["version"])
         ) {
             return true;
         }
@@ -1282,7 +1320,7 @@ class project extends base
     {
         $this->log(__FUNCTION__ . "($bIgnoreCache) start");
         $this->_initVcs();
-        if ($this->_oVcs) {
+        if (isset($this->_oVcs) && $this->_oVcs) {
             if (!method_exists($this->_oVcs, "getRemoteBranches")) {
                 // the version control class does not have this method
                 return false;
@@ -1303,15 +1341,15 @@ class project extends base
         $this->log(__FUNCTION__ . "($bRefresh) start");
 
         if (!$this->_aPrjConfig["build"]["type"]) {
-            $this->_aData["phases"]["source"] = array("error" => t("class-project-error-repo-type-not-set"), );
+            $this->_aData["phases"]["source"] = ["error" => t("class-project-error-repo-type-not-set"),];
         } else {
             $this->_initVcs();
-            if ($this->_oVcs) {
+            if (isset($this->_oVcs) && $this->_oVcs) {
                 $this->_aData["phases"]["source"] = $this->_oVcs->getRepoRevision($bRefresh);
             } else {
-                $this->_aData["phases"]["source"] = array(
+                $this->_aData["phases"]["source"] = [
                     "error" => sprintf(t("class-project-error-repo-type-not-supported"), $this->_aPrjConfig["build"]["type"]),
-                );
+                ];
             }
         }
         $this->log(__FUNCTION__ . " result:<pre>" . print_r($this->_aData, 1) . "</pre>");
@@ -1320,19 +1358,19 @@ class project extends base
 
     /**
      * Initialize version control system (git, ...) if it is not initialized yet
-     * @return object vcs-object
+     * it sets the object $this->_oVcs
      */
-    protected function _initVcs(): object
+    protected function _initVcs(): void
     {
         $this->log(__FUNCTION__ . " start");
-        if (!$this->_oVcs) {
+        if (!isset($this->_oVcs)) {
             if (!$this->_aPrjConfig["build"]["type"]) {
-                $this->_aData["phases"]["source"] = array("error" => t("class-project-error-repo-type-not-set"), );
+                $this->_aData["phases"]["source"] = ["error" => t("class-project-error-repo-type-not-set"),];
             } else {
                 if (!@include_once("vcs." . $this->_aPrjConfig["build"]["type"] . ".class.php")) {
-                    $this->_aData["phases"]["source"] = array(
+                    $this->_aData["phases"]["source"] = [
                         "error" => sprintf(t("class-project-error-repo-type-not-supported"), $this->_aPrjConfig["build"]["type"]),
-                    );
+                    ];
                 } else {
                     $aConfig = $this->_aPrjConfig["build"];
                     // for vcs classes
@@ -1348,7 +1386,7 @@ class project extends base
                 }
             }
         }
-        return $this->_oVcs;
+        // return $this->_oVcs;
     }
 
     /**
@@ -1358,7 +1396,7 @@ class project extends base
      */
     public function getConfiguredPlugins(string $sSection = ''): array
     {
-        $aReturn = array();
+        $aReturn = [];
         if (!$sSection) {
             $aReturn = $this->_aConfig["plugins"];
         } else {
@@ -1387,7 +1425,7 @@ class project extends base
      */
     protected function _getSshKeys(): array
     {
-        $aReturn =[];
+        $aReturn = [];
         foreach (glob($this->_aConfig["dataDir"] . "/sshkeys/*.pub") as $filename) {
             $aReturn[] = str_replace(".pub", "", basename($filename));
         }
@@ -1409,14 +1447,14 @@ class project extends base
             $this->_logaction($sError, __FUNCTION__, "error");
             return false;
         }
-        $aDeploytimes = array();
-        if (array_key_exists("deploytimes", $this->_aConfig["phases"][$sPhase])) {
-            $aDeploytimes = $this->_aConfig["phases"][$sPhase]["deploytimes"];
-        }
+
+        $aDeploytimes = $this->_aConfig["phases"][$sPhase]["deploytimes"] ?? [];
+
         if (
-            array_key_exists("deploytimes", $this->_aPrjConfig["phases"][$sPhase]) && $this->_aPrjConfig["phases"][$sPhase]["deploytimes"]
+            isset($this->_aPrjConfig["phases"][$sPhase]["deploytimes"])
+            && $this->_aPrjConfig["phases"][$sPhase]["deploytimes"]
         ) {
-            $aDeploytimes = array($this->_aPrjConfig["phases"][$sPhase]["deploytimes"]);
+            $aDeploytimes = [$this->_aPrjConfig["phases"][$sPhase]["deploytimes"]];
         }
         return $aDeploytimes;
     }
@@ -1454,14 +1492,14 @@ class project extends base
      */
     protected function _ldapProjectSearch(string $sSearchFilter): bool|array
     {
-        $aReturn = array();
+        $aReturn = [];
         require_once("ldap.class.php");
         $oLdapIML = new imlldap($this->_aConfig['projects']['ldap']);
         // $oLdapIML->debugOn();
         $aResultsIml = $oLdapIML->searchDn(
             $this->_aConfig['projects']['ldap']['DnProjects'],
             $sSearchFilter,
-            array("*")
+            ["*"]
         );
         if (!$aResultsIml['count']) {
             return false;
@@ -1471,13 +1509,13 @@ class project extends base
         /*
           unset($aResultsIml['count']);
           foreach ($aResultsIml as $aItem) {
-          $aReturn[$aItem['cn'][0]] = array(
+          $aReturn[$aItem['cn'][0]] = [
           'dn' => $aItem['dn'],
           'cn' => $aItem['cn'][0],
           '_description' => $aItem['description'][0],
           'title' => $sTitle,
           'description' => $sDescription,
-          );
+          ];
           }
           $oLdapIML->close();
           ksort($aReturn);
@@ -1520,9 +1558,7 @@ class project extends base
             $sQuery = '(&(objectclass=hieraSource)(documentIdentifier=' . $sId . '))';
             $aResult = $this->_ldapProjectSearch($sQuery);
             // echo '<pre>$aResult = ' . print_r($aResult, 1) . '</pre>';
-            if (
-                is_array($aResult) && $aResult[0] && array_key_exists('hieradata', $aResult[0])
-            ) {
+            if (isset($aResult[0]['hieradata'])) {
                 foreach ($aResult[0]['hieradata'] as $sLine) {
                     // echo $sLine.'<br>';
                     if (preg_match('/^cfg=/', $sLine)) {
@@ -1545,16 +1581,16 @@ class project extends base
         $sPluginName = (isset($this->_aPrjConfig['deploy']['enabled_rollout_plugin']) && $this->_aPrjConfig['deploy']['enabled_rollout_plugin'])
             ? $this->_aPrjConfig['deploy']['enabled_rollout_plugin']
             : 'default';
-        $this->oRolloutPlugin = false;
+        unset($this->oRolloutPlugin);
         try {
             require_once $this->_getPluginFilename('rollout', $sPluginName);
             $sPluginClassname = 'rollout_' . $sPluginName;
-            $this->oRolloutPlugin = new $sPluginClassname(array(
+            $this->oRolloutPlugin = new $sPluginClassname([
                 'lang' => $this->_aConfig['lang'],
                 'phase' => false,
                 'globalcfg' => isset($this->_aConfig['plugins']['rollout'][$sPluginName]) ? $this->_aConfig['plugins']['rollout'][$sPluginName] : [],
                 'projectcfg' => $this->_aPrjConfig,
-            ));
+            ]);
             // print_r($this->_oRolloutPlugin->getPluginfos());
             // print_r($this->_oRolloutPlugin->getName());
         } catch (Exception $ex) {
@@ -1570,7 +1606,7 @@ class project extends base
     public function setBranchname(string $sBranchname): string
     {
         $this->_sBranchname = $sBranchname;
-        if ($this->_oVcs) {
+        if (isset($this->_oVcs) && $this->_oVcs) {
             if (method_exists($this->_oVcs, "setCurrentBranch")) {
                 $this->_oVcs->setCurrentBranch($sBranchname);
             }
@@ -1583,12 +1619,14 @@ class project extends base
     // ----------------------------------------------------------------------
 
     /**
-     * send data to a tempfile for ajax polling
-     * @param type $sTmpFile
-     * @param type $sData
-     * @return boolean
+     * Store data to a tempfile (read by for ajax polling) and update actions box
+     * 
+     * @param  string  $sData     full output of all so far executed shell commands
+     * @param  array   $aActions  for right output box: Array of actions with marker of current action
+     *                            see build() method for the structure
+     * @return bool|int
      */
-    protected function _TempFill($sData, $aActions = array())
+    protected function _TempFill(string $sData, array $aActions = []): bool|int
     {
         if (!$this->_sProcessTempOut) {
             return false;
@@ -1615,12 +1653,13 @@ class project extends base
     }
 
     /**
-     * delete tempfile for ajax polling; if a directory is given as parameter
-     * the tmp file will be moved there 
+     * Delete tempfile for ajax polling; if a directory is given as parameter
+     * the tmp file will be moved there.
+     * 
      * @param string  $sTempDir  optional; target dir to copy; default=false (=delete file)
      * @return boolean
      */
-    protected function _TempDelete($sTempDir = false)
+    protected function _TempDelete(string $sTempDir = ''): bool
     {
         if (!$this->_sProcessTempOut) {
             return false;
@@ -1636,15 +1675,16 @@ class project extends base
     }
 
     /**
-     * get the name of the current branch (or default branch)
-     * @param bool  $bReturnMasterIfEmpty  flag: if there is no current branch then detect a master branch
-     * @return string
+     * Get the name of the current branch (or default branch).
+     * It returns false if the vcs was not initialized yet.
+     * 
+     * @return string|bool
      */
-    public function getBranchname($bReturnMasterIfEmpty = false)
+    public function getBranchname(): string|bool
     {
         $this->log(__FUNCTION__ . " start");
         $this->_initVcs();
-        if ($this->_oVcs) {
+        if (isset($this->_oVcs) && $this->_oVcs) {
             if (method_exists($this->_oVcs, "getCurrentBranch")) {
                 $sCurrentBranch = $this->_oVcs->getCurrentBranch(true); // true means search for master branch if empty
                 if ($sCurrentBranch) {
@@ -1660,10 +1700,11 @@ class project extends base
      * Build a new package for the deployment. It will be put to the queue
      * of the first active phase (i.e. preview).
      * If there is no deployment time range it will be deployed too.
-     * @global type $aParams
-     * @return boolean|string
+     * 
+     * @global string $sTmpFile
+     * @return boolean|string false or HTML code
      */
-    public function build($sTmpFile = false)
+    public function build(string $sTmpFile = ''): bool|string
     {
         $this->log(__FUNCTION__ . " start");
         if (!$this->oUser->hasPermission("project-action-build")) {
@@ -1672,22 +1713,22 @@ class project extends base
         global $aParams;
         $sReturn = false;
 
-        $aActionList = array(
+        $aActionList = [
             'iActive' => 0,
             'label' => t('build'),
-            'actions' => array(
-                array('label' => t('class-project-build-label-cleanup-builds')),
-                array('label' => t('class-project-build-label-create-workdir')),
-                array('label' => t('class-project-build-label-get-sources-from-version-control')),
-                array('label' => t('class-project-build-label-execute-hook-postclone')),
-                array('label' => t('class-project-build-label-copy-default-structure')),
-                array('label' => t('class-project-build-label-execute-hook-precompress')),
-                array('label' => t('class-project-build-label-cleanup-project')),
-                array('label' => t('class-project-build-label-create-package')),
-                array('label' => t('class-project-build-label-remove-workdir')),
-                array('label' => t('class-project-build-label-queue-to-first-active-phase')),
-            ),
-        );
+            'actions' => [
+                ['label' => t('class-project-build-label-cleanup-builds')],
+                ['label' => t('class-project-build-label-create-workdir')],
+                ['label' => t('class-project-build-label-get-sources-from-version-control')],
+                ['label' => t('class-project-build-label-execute-hook-postclone')],
+                ['label' => t('class-project-build-label-copy-default-structure')],
+                ['label' => t('class-project-build-label-execute-hook-precompress')],
+                ['label' => t('class-project-build-label-cleanup-project')],
+                ['label' => t('class-project-build-label-create-package')],
+                ['label' => t('class-project-build-label-remove-workdir')],
+                ['label' => t('class-project-build-label-queue-to-first-active-phase')],
+            ],
+        ];
         $this->_setProcessOutFile($sTmpFile);
 
         $this->_iRcAll = 0;
@@ -1707,7 +1748,7 @@ class project extends base
         $this->_TempFill($sReturn, $aActionList);
 
         $this->_initVcs();
-        if (!$this->_oVcs) {
+        if (!isset($this->_oVcs) || !$this->_oVcs) {
             $sError = sprintf(t('class-project-error-build-type-not-supported'), $this->_aPrjConfig["build"]["type"]);
             $this->_logaction($sError, __FUNCTION__, "error");
             return $this->_oHtml->getBox("error", $sError . $sReturn);
@@ -1883,7 +1924,7 @@ class project extends base
         // cleanup .git, .svn, ...
         // --------------------------------------------------
         $sReturn .= '<h3>' . t('class-project-build-label-cleanup-project') . '</h3>';
-        if ($this->_oVcs) {
+        if (isset($this->_oVcs) && $this->_oVcs) {
             $this->_oVcs->cleanupWorkdir($sTempBuildDir);
         }
 
@@ -1898,13 +1939,10 @@ class project extends base
         // --------------------------------------------------
         $sReturn .= '<h3>' . t('class-project-build-label-create-package') . '</h3>';
         // public_html must exist
-        if (
-            array_key_exists('haspublic', $this->_aPrjConfig["build"])
-            && $this->_aPrjConfig["build"]["haspublic"][0]
-        ) {
+        if (isset($this->_aPrjConfig["build"]['haspublic'][0])) {
             $sWebroot = false;
-            $sWebroot1 = $sTempBuildDir . '/public_html';
-            $sWebroot2 = $sTempBuildDir . '/public';
+            $sWebroot1 = "$sTempBuildDir/public_html";
+            $sWebroot2 = "$sTempBuildDir/public";
             if (file_exists($sWebroot1)) {
                 $sWebroot = $sWebroot1;
             }
@@ -1937,7 +1975,7 @@ class project extends base
         $sInfoFileArchiv = $this->_getArchiveDir($sTs2) . '/' . basename($this->_getInfofile($sFirstLevel, "deployed"));
         $sPackageFileArchiv = $this->_getArchiveDir($sTs2) . '/' . basename($this->_getPackagefile($sFirstLevel, "deployed"));
 
-        $aInfos = array(
+        $aInfos = [
             'date' => $sTs,
             'version' => $sTs2,
             // 'branch' => $sBranch,
@@ -1950,7 +1988,7 @@ class project extends base
             'imagepart' => $aCivars['imagepart'],
 
             'message' => $aRepodata['message'],
-        );
+        ];
         /*
           "user": "' . $aParams["inputUser"] . '",
           "remark": "' . $aParams["inputComment"] . '"
@@ -1989,11 +2027,11 @@ class project extends base
             try {
                 include_once $this->_getPluginFilename('build', $sPluginName);
                 $sPluginClassname = 'build_' . $sPluginName;
-                $oPlugin = new $sPluginClassname(array(
+                $oPlugin = new $sPluginClassname([
                     'lang' => $this->_aConfig['lang'],
                     'workdir' => $sTempBuildDir,
                     'outfile' => $sPackageFileArchiv,
-                ));
+                ]);
             } catch (Exception $ex) {
                 return $this->_oHtml->getBox(
                     "error",
@@ -2063,23 +2101,24 @@ class project extends base
     }
 
     /**
-     * put a packaged version into the queue of a specified phase
-     * @param string $sPhase    name of the phase
+     * Put a packaged version into the queue of a specified phase
+     * 
+     * @param string $sPhase    name of the phase that gets the new version
      * @param string $sVersion  version 
-     * @return string
+     * @return string The HTML code
      */
-    public function queue($sPhase, $sVersion)
+    public function queue(string $sPhase, string $sVersion): string
     {
-        $aActionList = array(
+        $aActionList = [
             'iActive' => 0,
             'label' => t("queue"),
-            'actions' => array(
-                array('label' => t("class-project-queue-label-checks")),
-                array('label' => t("class-project-queue-label-remove-existing-version")),
-                array('label' => t("class-project-queue-label-link-new-version")),
-                array('label' => t("class-project-queue-label-deploy")),
-            ),
-        );
+            'actions' => [
+                ['label' => t("class-project-queue-label-checks")],
+                ['label' => t("class-project-queue-label-remove-existing-version")],
+                ['label' => t("class-project-queue-label-link-new-version")],
+                ['label' => t("class-project-queue-label-deploy")],
+            ],
+        ];
         $this->_logaction(t('starting') . " queue($sPhase, $sVersion)", __FUNCTION__);
         $sReturn = "<h2> " . t("queue") . " " . $this->getLabel() . " :: $sPhase</h2>";
         $this->_TempFill($sReturn, $aActionList);
@@ -2147,14 +2186,15 @@ class project extends base
     }
 
     /**
-     * deploy a queued package - this moves the queue into the repo directory
-     * and will be installed on server within 30 min.
+     * Deploy a queued package - this moves the queue into the repo directory.
      * This method checks the deploy times
-     * @param string $sPhase which queue of which phase we want to install in server
+     * It returns the output to show in browser
+     * 
+     * @param string $sPhase              the queue of which phase we want to install in server
      * @param bool   $bIgnoreDeploytimes  flag; if true it will override time windows
-     * @return boolean|string
+     * @return string The HTML output
      */
-    public function deploy($sPhase, $bIgnoreDeploytimes = false)
+    public function deploy(string $sPhase, bool $bIgnoreDeploytimes = false): string
     {
         $this->log(__FUNCTION__ . " start");
         if (
@@ -2162,16 +2202,16 @@ class project extends base
         ) {
             return $this->oUser->showDenied();
         }
-        $aActionList = array(
+        $aActionList = [
             'iActive' => 0,
             'label' => t("deploy"),
-            'actions' => array(
-                array('label' => t("class-project-deploy-label-checks")),
-                array('label' => t("class-project-deploy-label-activate-queued-version")),
-                array('label' => t("class-project-deploy-label-synch-packages")),
-                array('label' => t("class-project-deploy-label-install-on-target")),
-            ),
-        );
+            'actions' => [
+                ['label' => t("class-project-deploy-label-checks")],
+                ['label' => t("class-project-deploy-label-activate-queued-version")],
+                ['label' => t("class-project-deploy-label-synch-packages")],
+                ['label' => t("class-project-deploy-label-install-on-target")],
+            ],
+        ];
         $sReturn = "<h2>" . t("deploy") . " " . $this->getLabel() . " :: $sPhase</h2>";
         $this->_TempFill($sReturn, $aActionList);
 
@@ -2267,10 +2307,10 @@ class project extends base
         // synch packages
         // --------------------------------------------------
         // $sReturn.=$this->_execAndSend("ln -s $sLinkTarget $sLinkName");
-        if (array_key_exists('mirrorPackages', $this->_aConfig) && count($this->_aConfig['mirrorPackages'])) {
+        if (isset($this->_aConfig['mirrorPackages']) && count($this->_aConfig['mirrorPackages'])) {
             foreach ($this->_aConfig['mirrorPackages'] as $sLabel => $aTarget) {
                 $sReturn .= '<h3>' . sprintf(t("class-project-info-deploy-synching-package"), $sLabel) . "</h3>";
-                if (array_key_exists('type', $aTarget)) {
+                if (isset($aTarget['type'])) {
                     $sCmd = false;
                     // $sSource=$this->_aConfig["packageDir"]."/$sPhase/*";
                     $sSource = $sRepoLink;
@@ -2303,7 +2343,7 @@ class project extends base
         // --------------------------------------------------
         // run action to install
         // --------------------------------------------------
-        $sDeploymethod = array_key_exists("deploymethod", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["deploymethod"] : "none";
+        $sDeploymethod = isset($this->_aPrjConfig["phases"][$sPhase]["deploymethod"]) ? $this->_aPrjConfig["phases"][$sPhase]["deploymethod"] : "none";
         // $sTargethosts = array_key_exists("hosts", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["hosts"] : '';
 
         $sReturn .= '<h3>' . t("class-project-info-deploy-start-by-method") . ' :: ' . $sDeploymethod . '</h3>'
@@ -2370,12 +2410,13 @@ class project extends base
     }
 
     /**
-     * accept a the installed version in a phase and put this version
+     * Accept a the installed version of the given phase and put this version
      * to the queue of the next phase.
-     * @param string $sPhase which queue of which phase we want to install in server
-     * @return type
+     * 
+     * @param  string  $sPhase  phase to accept to be rolled out on the next phase
+     * @return string The HTML code
      */
-    public function accept($sPhase)
+    public function accept(string $sPhase): string
     {
         $this->log(__FUNCTION__ . " start");
         if (
@@ -2411,22 +2452,26 @@ class project extends base
     }
 
     /**
-     * save POSTed data as project config
-     * @return boolean
+     * Save data as project config.
+     * If no data were given then $_POST is used.
+     * It returns bool with success state or a string with deny error message
+     * 
+     * @param  array  $aData  optional: data to write
+     * @return boolean|string
      */
-    public function saveConfig($aData = false)
+    public function saveConfig(array $aData = []): bool|string
     {
         $this->log(__FUNCTION__ . " start");
         if (!$this->oUser->hasPermission("project-action-setup")) {
             return $this->oUser->showDenied();
         }
         $this->_logaction(t('starting') . " saveConfig(...)", __FUNCTION__);
-        if (!$aData) {
+        if (!count($aData)) {
             $aData = $_POST;
         }
 
-        foreach (array('id', 'label', 'description', 'contact', 'build', 'fileprefix', 'phases') as $sKey) {
-            if (!array_key_exists($sKey, $aData)) {
+        foreach (['id', 'label', 'description', 'contact', 'build', 'fileprefix', 'phases'] as $sKey) {
+            if (!isset($aData[$sKey])) {
                 $this->_logaction(t('abortet') . " missing key $sKey in savedata", __FUNCTION__, "error");
                 return false;
             }
@@ -2434,8 +2479,8 @@ class project extends base
         $sId = $aData["id"];
 
         // remove unwanted items
-        foreach (array("setupaction", "prj", "id") as $s) {
-            if (array_key_exists($s, $aData)) {
+        foreach (["setupaction", "prj", "id"] as $s) {
+            if (isset($aData[$s])) {
                 unset($aData[$s]);
             }
         }
@@ -2458,17 +2503,17 @@ class project extends base
 
 
             $sDn = 'documentIdentifier=' . $sId . ',' . $this->_aConfig['projects']['ldap']['DnProjects'];
-            $aItem = array(
-                'objectClass' => array(
+            $aItem = [
+                'objectClass' => [
                     'document',
                     'hieraSource',
                     'top',
-                ),
-                'hieraData' => array(
+                ],
+                'hieraData' => [
                     'cfg=' . json_encode($aData),
                     'updated=' . date("Y-m-d H:i:s") . ' by ' . $this->oUser->getUsername(),
-                )
-            );
+                ]
+            ];
 
             require_once("ldap.class.php");
             $oLdapIML = new imlldap($this->_aConfig['projects']['ldap']);
@@ -2505,12 +2550,13 @@ class project extends base
     }
 
     /**
-     * create a new project; it returns the error message if it fails and
+     * Create a new project; it returns the error message if it fails and
      * an empty string if it was successful.
+     * 
      * @param string  $sId  id
      * @return string
      */
-    public function create($sId)
+    public function create(string $sId): string
     {
         $this->log(__FUNCTION__ . " start");
         if (!$this->oUser->hasPermission("project-action-create")) {
@@ -2543,24 +2589,24 @@ class project extends base
         $this->_readConfig();
         $this->_aConfig["id"] = $sId;
 
-        $this->_aPrjConfig = array(
+        $this->_aPrjConfig = [
             "id" => $sId, // for saveConfig
             "label" => "$sId",
             "fileprefix" => "$sId",
             "description" => '',
             "contact" => '',
-            "build" => array(
+            "build" => [
                 "type" => "",
                 "ssh" => "",
                 "auth" => "",
                 "webaccess" => "",
-            ),
-            "phases" => array(
-                "preview" => array(),
-                "stage" => array(),
-                "live" => array(),
-            ),
-        );
+            ],
+            "phases" => [
+                "preview" => [],
+                "stage" => [],
+                "live" => [],
+            ],
+        ];
         $this->_verifyConfig(); // check skeleton
         $bReturn = $this->saveConfig($this->_aPrjConfig);
         if (!$bReturn) {
@@ -2575,11 +2621,15 @@ class project extends base
     }
 
     /**
-     * delete a project; it returns a string with errormessage; false = no error
-     * @param array $aOptions
-     * @return boolean|string
+     * Delete a project; it returns a string with errormessage; empty string = no error
+     * 
+     * @param array $aOptions  array with enabled actions
+     *                         - bRemoveRepolinks
+     *                         - bRemoveArchive
+     *                         - bRemoveConfig
+     * @return string
      */
-    public function delete($aOptions = array())
+    public function delete(array $aOptions = []): string
     {
         $this->log(__FUNCTION__ . " start");
         if (!$this->oUser->hasPermission("project-action-delete")) {
@@ -2591,9 +2641,9 @@ class project extends base
         }
         $this->_logaction(t('starting') . " delete()", __FUNCTION__);
 
-        // (array("bRemoveRepolinks", "bRemoveArchive", "bRemoveConfig")
+        // ["bRemoveRepolinks", "bRemoveArchive", "bRemoveConfig"]
         // --- remove links in phases directory to built archives
-        if (array_key_exists("bRemoveRepolinks", $aOptions) && $aOptions["bRemoveRepolinks"]) {
+        if (isset($aOptions["bRemoveRepolinks"]) && $aOptions["bRemoveRepolinks"]) {
             echo "DELETE Repo-Links ...<br>";
 
             foreach (array_keys($this->getPhases()) as $sPhase) {
@@ -2610,11 +2660,11 @@ class project extends base
                 }
             }
         }
-        if (array_key_exists("bRemoveArchive", $aOptions) && $aOptions["bRemoveArchive"]) {
+        if (isset($aOptions["bRemoveArchive"]) && $aOptions["bRemoveArchive"]) {
             echo "DELETE built Archives ...<br>";
             $this->cleanupArchive(true); // true to delete all
         }
-        if (array_key_exists("bRemoveConfig", $aOptions) && $aOptions["bRemoveConfig"]) {
+        if (isset($aOptions["bRemoveConfig"]) && $aOptions["bRemoveConfig"]) {
             echo "DELETE Config ...<br>";
             // echo "config file: $sCfgfile<br>";
             if (file_exists($sCfgfile . ".ok")) {
@@ -2632,6 +2682,6 @@ class project extends base
         }
         $this->_sendMessage(t('finished') . " delete()");
         $this->_logaction(t('finished') . " delete()", __FUNCTION__, "success");
-        return false;
+        return '';
     }
 }
-- 
GitLab