WEB: Add typing

This commit is contained in:
Le Philousophe
2025-08-11 12:10:23 +02:00
parent 51ce727edd
commit cc9fa80181
45 changed files with 463 additions and 239 deletions
+32 -17
View File
@@ -2,6 +2,7 @@
namespace ScummVM;
use Smarty\Smarty;
use Smarty\Template;
use ScummVM\Models\SimpleYamlModel;
use ScummVM\SiteUtils;
@@ -12,11 +13,13 @@ use ScummVM\SiteUtils;
*/
class Controller
{
protected $template;
private $smarty;
private $css_files;
private $js_files;
private $menuModel;
protected string $template;
private Smarty $smarty;
/** @var string[] */
private array $css_files;
/** @var string[] */
private array $js_files;
private SimpleYamlModel $menuModel;
/**
* Constructor that will create a Smarty object and configure it according
@@ -102,7 +105,7 @@ class Controller
/**
* Checks whether a locale string is RTL or LTR
*/
private function isRtl($localeName)
private function isRtl(string $localeName): bool
{
$rtl_chars_pattern = '/[\x{0590}-\x{05ff}\x{0600}-\x{06ff}]/u';
return preg_match($rtl_chars_pattern, $localeName) === 1;
@@ -111,7 +114,7 @@ class Controller
/**
* Smarty outputfilter, run just before displaying.
*/
public function outputFilter($string, $smarty)
public function outputFilter(string $string, Template $smarty): string
{
/* Properly encode all ampersands as "&". */
$string = preg_replace('/&(?!([a-z]+|(#\d+));)/i', '&', $string);
@@ -122,7 +125,7 @@ class Controller
/**
* Formating of dateAs, registered as a modifier for Smarty templates.
*/
public function dateLocalizedSmartyModifier($timestamp)
public function dateLocalizedSmartyModifier(int $timestamp): string
{
global $lang;
$formatter = datefmt_create($lang, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::NONE);
@@ -132,7 +135,7 @@ class Controller
/**
* Formating of download URLs, registered as a modifier for Smarty templates.
*/
public function downloadsSmartyModifier($path)
public function downloadsSmartyModifier(string $path): string
{
if (\strpos($path, "http") === 0) {
return $path;
@@ -148,7 +151,7 @@ class Controller
/**
* Formating of version, registered as a modifier for Smarty templates.
*/
public function releaseSmartyModifier($string)
public function releaseSmartyModifier(string $string): string
{
$string = preg_replace("/\{[$]?release\}/", RELEASE, $string);
$string = preg_replace("/\{[$]?release_tools\}/", RELEASE_TOOLS, $string);
@@ -156,7 +159,7 @@ class Controller
}
/* Render the HTML using the template and any set variables and displays it. */
public function display($content)
public function display(string $content): void
{
$vars = array(
'css_files' => $this->css_files,
@@ -168,7 +171,10 @@ class Controller
}
/* Render the HTML using the template and any set variables and returns it. */
public function fetch($template, $vars = null)
/**
* @param ?array<string, mixed> $vars
*/
public function fetch(string $template, ?array $vars = null): string
{
if (!is_null($vars)) {
$this->smarty->assign($vars);
@@ -177,13 +183,19 @@ class Controller
}
/* Set up the variables used by the template and render the page. */
public function renderPage($vars)
/**
* @param ?array<string, mixed> $vars
*/
public function renderPage(?array $vars): void
{
$this->display($this->fetch($this->template, $vars));
}
/* Assign extra CSS files needed by the different pages/templates. */
public function addCSSFiles($extra_css)
/**
* @param string|string[] $extra_css
*/
public function addCSSFiles(string|array $extra_css): void
{
if (is_array($extra_css)) {
$this->css_files = array_merge(
@@ -196,7 +208,10 @@ class Controller
}
/* Assign javascripts files needed by the different pages/templates. */
public function addJSFiles($extra_js)
/**
* @param string|string[] $extra_js
*/
public function addJSFiles(string|array $extra_js): void
{
if (is_array($extra_js)) {
$this->js_files = array_merge(
@@ -208,12 +223,12 @@ class Controller
}
}
protected function getConfigVars($title)
protected function getConfigVars(string $title): ?string
{
return $this->smarty->getConfigVars($title);
}
protected function getHeadline($body)
protected function getHeadline(string $body): string
{
$headline = '';
for ($line = \strtok($body, PHP_EOL); $line !== false; $line = \strtok(PHP_EOL)) {
+4 -3
View File
@@ -10,6 +10,7 @@ use League\Csv\Statement;
use Symfony\Component\Yaml\Yaml;
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
use GuzzleHttp\Psr7\Response;
use Propel\Runtime\Propel;
use Propel\Runtime\Connection\Exception\RollbackException;
use Propel\Runtime\Map\TableMap;
@@ -59,7 +60,7 @@ class DataUtils
*
* @return void
*/
public static function updateData()
public static function updateData(): void
{
$client = new Client();
$promises = [];
@@ -78,7 +79,7 @@ class DataUtils
\file_put_contents('.clear-cache', '');
}
private static function doUpdateData($name, $response)
private static function doUpdateData(string $name, Response $response): void
{
$tsv = $response->getBody();
$reader = Reader::createFromString($tsv);
@@ -111,7 +112,7 @@ class DataUtils
\file_put_contents($outFile, $yaml);
}
private static function convertYamlToOrm()
private static function convertYamlToOrm(): void
{
foreach (self::OBJECT_NAMES as $name => $object) {
$failures = array();
+3 -3
View File
@@ -8,10 +8,10 @@ use ScummVM\Pages\SimplePage;
*/
abstract class ExceptionHandler
{
private static $exception;
private static \Throwable $exception;
/* If the MenuModel cause the exception we need to skip them. */
public static function skipMenus()
public static function skipMenus(): bool
{
if (!isset(self::$exception)) {
return false;
@@ -33,7 +33,7 @@ abstract class ExceptionHandler
}
/* Handle exceptions. */
public static function handleException($e)
public static function handleException(\Throwable $e): void
{
self::$exception = $e;
+6 -6
View File
@@ -16,7 +16,7 @@ class FileUtils
* @param $path the path to the file that will be analyzed
* @return bool whether or not the file exists
*/
public static function exists($path)
public static function exists(string $path): bool
{
$path = FileUtils::toAbsolutePathIfOnServer($path);
return is_file($path) && is_readable($path);
@@ -28,7 +28,7 @@ class FileUtils
* @param $path the path to the file that will be analyzed
* @return string the file size in a human-readable form
*/
public static function getFileSize($path)
public static function getFileSize(string $path): string
{
$path = FileUtils::toAbsolutePathIfOnServer($path);
// Get the file size, rounded to the nearest kilobyte
@@ -55,7 +55,7 @@ class FileUtils
* @param $path the path to the file that will be analyzed
* @return string the extension
*/
public static function getExtension($path)
public static function getExtension(string $path): string
{
$path = FileUtils::toAbsolutePathIfOnServer($path);
// Get everything to the right of the last period
@@ -74,7 +74,7 @@ class FileUtils
* @param $path the path to the file that will be analyzed
* @return string the SHA-256 hash
*/
public static function getSha256($path)
public static function getSha256(string $path): string
{
$path = FileUtils::toAbsolutePathIfOnServer($path);
// Check if we already have a generated hash file
@@ -97,7 +97,7 @@ class FileUtils
* @param $path the path to the file that will be analyzed
* @return string the date
*/
public static function getLastModified($path)
public static function getLastModified(string $path): string
{
$path = FileUtils::toAbsolutePathIfOnServer($path);
$date = new DateTime();
@@ -116,7 +116,7 @@ class FileUtils
* @param $path the relative path to the file that will be analyzed
* @return string the path of the file, either relative or absolute
*/
private static function toAbsolutePathIfOnServer($relativePath)
private static function toAbsolutePathIfOnServer(string $relativePath): string
{
return is_file(DIR_SERVER_ROOT . '/'. $relativePath) ? DIR_SERVER_ROOT . '/'. $relativePath : $relativePath;
}
+9 -6
View File
@@ -9,11 +9,11 @@ use Erusev\Parsedown;
class LocalizationUtils
{
private static $purifier;
private static \HTMLPurifier $purifier;
const NO_FILES = 'No Localization Files Found';
public static function localize()
public static function localize(): void
{
$config = \HTMLPurifier_Config::createDefault();
self::$purifier = new \HTMLPurifier($config);
@@ -27,7 +27,7 @@ class LocalizationUtils
}
}
private static function convertLanguageJsonToSmartyIni($lang)
private static function convertLanguageJsonToSmartyIni(string $lang): void
{
$Parsedown = new \Parsedown();
$Parsedown->setBreaksEnabled(true);
@@ -46,7 +46,7 @@ class LocalizationUtils
file_put_contents(join(DIRECTORY_SEPARATOR, [DIR_DATA, $lang, "strings.ini"]), $output);
}
private static function updateNewsL10n($lang)
private static function updateNewsL10n(string $lang): void
{
$newsFile = join(DIRECTORY_SEPARATOR, [DIR_DATA, $lang, "news.json"]);
// For non-english, create/overwrite JSON files from our l10n file
@@ -79,7 +79,7 @@ class LocalizationUtils
if ($lang === 'fr') {
$content = preg_replace_callback(
"/(?<=\(http)(.*?)(?=\))/u",
function ($matches) {
function (array $matches): string {
return preg_replace("/\x{202f}/u", "", $matches[1]);
},
$content
@@ -114,7 +114,10 @@ class LocalizationUtils
}
}
private static function getAllNews($lang)
/**
* @return array<string, array{'title': string, 'content': string}>
*/
private static function getAllNews(string $lang): array
{
$dir = join(DIRECTORY_SEPARATOR, [DIR_DATA, $lang, 'news']);
+4 -4
View File
@@ -10,7 +10,7 @@ abstract class BasicModel
{
const FILE_NOT_FOUND = 'The filename %s could not be found';
protected static $cache;
protected static Psr16Adapter $cache;
public function __construct()
{
@@ -34,7 +34,7 @@ abstract class BasicModel
}
}
protected function getLocalizedFile($filename)
protected function getLocalizedFile(string $filename): string
{
global $lang;
if (!$lang) {
@@ -51,7 +51,7 @@ abstract class BasicModel
}
}
protected function saveToCache($data, $key = '')
protected function saveToCache(mixed $data, string $key = ''): void
{
if ($key) {
$key = "_$key";
@@ -62,7 +62,7 @@ abstract class BasicModel
self::$cache->set($cacheKey, $data, 3600);
}
protected function getFromCache($key = '')
protected function getFromCache(string $key = ''): mixed
{
if (\file_exists(DIR_BASE . '/.no-cache')) {
return null;
+10 -4
View File
@@ -2,6 +2,9 @@
namespace ScummVM\Models;
use Propel\Runtime\ActiveQuery\Criteria;
use Propel\Runtime\Collection\Collection;
use ScummVM\OrmObjects\Compatibility;
use ScummVM\OrmObjects\CompatibilityQuery;
use ScummVM\OrmObjects\VersionQuery;
@@ -14,13 +17,13 @@ class CompatibilityModel extends BasicModel
const NO_VERSION_TARGET = 'No version and/or target specified.';
const NOT_FOUND = 'Did not find any games for the specified version.';
public function getLastUpdated()
public function getLastUpdated(): int|false
{
return filemtime($this->getLocalizedFile("compatibility.yaml"));
}
/* Get all the groups and the respectively demos for the specified ScummVM version. */
public function getAllData($version)
public function getAllData(string $version): Collection
{
$data = $this->getFromCache($version);
if (\is_null($data)) {
@@ -51,7 +54,7 @@ class CompatibilityModel extends BasicModel
}
/* Get a specific CompatGame-object for the requested version. */
public function getGameData($version, $target)
public function getGameData(?string $version, ?string $target): Compatibility
{
if (!is_string($version) || !is_string($target)) {
throw new \ErrorException(self::NO_VERSION_TARGET);
@@ -78,7 +81,10 @@ class CompatibilityModel extends BasicModel
return $gameData;
}
public function getAllDataGroups($version)
/**
* @return array<string, array<Compatibility>>
*/
public function getAllDataGroups(string $version): array
{
$data = $this->getAllData($version);
$compat_data = [];
+13 -3
View File
@@ -1,15 +1,22 @@
<?php
namespace ScummVM\Models;
use ScummVM\OrmObjects\DirectorDemo;
use ScummVM\OrmObjects\DirectorDemoQuery;
use Propel\Runtime\Collection\Collection;
/**
* The DirectorDemosModel class will generate DirectorDemos objects.
*/
class DirectorDemosModel extends BasicModel
{
/* Get all the groups and their respective demos. */
public function getAllGroupsAndDemos()
/**
* Get all the groups and their respective demos.
*
* @return array<?int, array{'name': string, 'href': ?int, 'demos': DirectorDemo[]}>
*/
public function getAllGroupsAndDemos(): array
{
$groupedData = $this->getFromCache();
if (is_null($groupedData)) {
@@ -23,7 +30,10 @@ class DirectorDemosModel extends BasicModel
return $groupedData;
}
private function createGroups($demos)
/**
* @return array<?int, array{'name': string, 'href': ?int, 'demos': DirectorDemo[]}>
*/
private function createGroups(Collection $demos): array
{
$groups = [];
foreach ($demos as $demo) {
+12 -3
View File
@@ -13,7 +13,10 @@ use ScummVM\OrmObjects\DownloadQuery;
class DownloadsModel extends BasicModel
{
/* Get all download entries. */
public function getAllDownloads()
/**
* @return array<string, DownloadsSection>
*/
public function getAllDownloads(): array
{
$sections = $this->getFromCache();
if (is_null($sections)) {
@@ -71,7 +74,10 @@ class DownloadsModel extends BasicModel
return $sections;
}
private function getSectionData()
/**
* @return array<string, array{'title': string, 'notes'?: string}>
*/
private function getSectionData(): array
{
return [
"current"=>["title"=>"{#downloadsXMLTitle#} {#downloadsXMLVersion#}"],
@@ -97,7 +103,10 @@ class DownloadsModel extends BasicModel
}
/* Get the recommended download */
public function getRecommendedDownload()
/**
* @return ?array{'os': string, 'version': string, 'extra_text': string, 'url': string}
*/
public function getRecommendedDownload(): ?array
{
if (!isset($_SERVER['HTTP_USER_AGENT'])) {
return null;
+14 -4
View File
@@ -1,15 +1,22 @@
<?php
namespace ScummVM\Models;
use ScummVM\OrmObjects\Demo;
use ScummVM\OrmObjects\DemoQuery;
use Propel\Runtime\Collection\Collection;
/**
* The GameDemosModel class will generate GameDemo objects.
* The GameDemosModel class will generate Demo objects.
*/
class GameDemosModel extends BasicModel
{
/* Get all the groups and their respective demos. */
public function getAllGroupsAndDemos()
/**
* Get all the groups and their respective demos.
*
* @return array<?int, array{'name': string, 'href': ?int, 'demos': Demo[]}>
*/
public function getAllGroupsAndDemos(): array
{
$groupedData = $this->getFromCache();
if (is_null($groupedData)) {
@@ -24,7 +31,10 @@ class GameDemosModel extends BasicModel
return $groupedData;
}
private function createGroups($demos)
/**
* @return array<?int, array{'name': string, 'href': ?int, 'demos': Demo[]}>
*/
private function createGroups(Collection $demos): array
{
$groups = [];
foreach ($demos as $demo) {
+9 -1
View File
@@ -2,6 +2,7 @@
namespace ScummVM\Models;
use ScummVM\Objects\DownloadsSection;
use ScummVM\OrmObjects\GameDownload;
use ScummVM\OrmObjects\GameDownloadQuery;
/**
@@ -9,7 +10,11 @@ use ScummVM\OrmObjects\GameDownloadQuery;
*/
class GameDownloadsModel extends BasicModel
{
/* Get all download entries. */
/**
* Get all download entries.
*
* @return array<string, DownloadsSection>
*/
public function getAllDownloads()
{
$sections = $this->getFromCache();
@@ -56,6 +61,9 @@ class GameDownloadsModel extends BasicModel
return $sections;
}
/**
* @return array<string, array{'title'?: string, 'notes'?: string}>
*/
private function getSectionData()
{
return [
+7 -2
View File
@@ -1,6 +1,7 @@
<?php
namespace ScummVM\Models;
use ScummVM\OrmObjects\Game;
use ScummVM\OrmObjects\GameQuery;
/**
@@ -8,8 +9,12 @@ use ScummVM\OrmObjects\GameQuery;
*/
class GameModel extends BasicModel
{
/* Get all Games from YAML */
public function getAllGames()
/**
* Get all Games from YAML
*
* @return Game[]
*/
public function getAllGames(): array
{
$data = $this->getFromCache();
if (is_null($data)) {
+6 -2
View File
@@ -10,8 +10,12 @@ use Symfony\Component\Yaml\Yaml;
*/
class LinksModel extends BasicModel
{
/* Get all the groups and the respectively demos. */
public function getAllGroupsAndLinks()
/**
* Get all the groups and the respectively demos.
*
* @return array<array{'name': string, 'notes': string, 'links': array<WebLink>}>
*/
public function getAllGroupsAndLinks(): array
{
$entries = $this->getFromCache();
if (is_null($entries)) {
+19 -7
View File
@@ -12,8 +12,12 @@ class NewsModel extends BasicModel
const INVALID_DATE = 'Invalid date, use yyyyMMdd. or yyyyMMddHHmm';
const FILE_NOT_FOUND = 'The requested news file doesn\'t exist.';
/* Get a list of all the available news files. */
private function getListOfNewsFilenames()
/**
* Get a list of all the available news files.
*
* @return string[]
*/
private function getListOfNewsFilenames(): array
{
if (!($files = scandir(join(DIRECTORY_SEPARATOR, [DIR_DATA, DEFAULT_LOCALE, 'news'])))) {
throw new \ErrorException(self::NO_FILES);
@@ -29,8 +33,12 @@ class NewsModel extends BasicModel
return $filenames;
}
/* Get all news items ordered by date, descending. */
public function getAllNews($processContent = false)
/**
* Get all news items ordered by date, descending.
*
* @return News[]
*/
public function getAllNews(bool $processContent = false): array
{
$news = $this->getFromCache();
if (is_null($news)) {
@@ -61,8 +69,12 @@ class NewsModel extends BasicModel
return $news;
}
/* Get the latest number of news items, or if no number is specified get all news items. */
public function getLatestNews($num = -1, $processContent = false)
/**
* Get the latest number of news items, or if no number is specified get all news items.
*
* @return News[]
*/
public function getLatestNews(int $num = -1, bool $processContent = false): array
{
if ($num == -1) {
return $this->getAllNews($processContent);
@@ -81,7 +93,7 @@ class NewsModel extends BasicModel
}
/* Get the news item that was posted on a specific date. */
public function getOneByFilename($filename, $processContent = false)
public function getOneByFilename(?string $filename, bool $processContent = false): News
{
if (is_null($filename) || !preg_match('/^\d{8,12}[a-z]?$/', $filename)) {
throw new \ErrorException(self::INVALID_DATE);
+23 -11
View File
@@ -5,7 +5,6 @@ use ScummVM\OrmObjects\GameQuery;
use ScummVM\OrmObjects\Screenshot;
use ScummVM\OrmObjects\ScreenshotQuery;
use Propel\Runtime\Collection\Collection;
use Propel\Runtime\Collection\ObjectCollection;
/**
* The ScreenshotsModel will generate Screenshot objects.
@@ -16,7 +15,11 @@ class ScreenshotsModel extends BasicModel
const INVALID_CATEGORY = 'Invalid category specified.';
const SUBCATEGORY_COLUMN = '(case when game.series_id is null then screenshot.id else game.series_id end)';
public function getAllCategories()
/**
* @return array<string, array{'title': string, 'category': string,
* 'games': array<string, array{'name': string, 'count': int}>}>
*/
public function getAllCategories(): array
{
$categories = ScreenshotQuery::create()->findCategories();
$data = [];
@@ -40,8 +43,12 @@ class ScreenshotsModel extends BasicModel
return $data;
}
/* Get all screenshots in one category. */
public function getScreenshotsByCompanyId($companyId)
/**
* Get all screenshots in one category.
*
* @return array{'title': string, 'category': string, 'games': array<string, Screenshot>}
*/
public function getScreenshotsByCompanyId(string $companyId): array
{
$cache_key = "c_{$companyId}";
$data = $this->getFromCache($cache_key);
@@ -65,8 +72,12 @@ class ScreenshotsModel extends BasicModel
return $data;
}
/* Get screenshots for a specific target. */
public function getScreenshotsBySubcategory($target)
/**
* Get screenshots for a specific target.
*
* @return Screenshot[]
*/
public function getScreenshotsBySubcategory(string $target)
{
$cache_key = "s_{$target}";
$data = $this->getFromCache($cache_key);
@@ -92,9 +103,8 @@ class ScreenshotsModel extends BasicModel
* Combines multiple screenshots into a single screenshot
*
* @param Collection $screenshots
* @return ?Screenshot
*/
private function combineScreenshots(iterable $screenshots)
private function combineScreenshots(iterable $screenshots): ?Screenshot
{
$count = $screenshots->count();
if ($count === 0) {
@@ -116,7 +126,7 @@ class ScreenshotsModel extends BasicModel
* combineSubcategories
*
* @param Collection $screenshots
* @return Screenshot[]
* @return array<string, Screenshot>
*/
private function combineSubcategories(iterable $screenshots)
{
@@ -158,8 +168,10 @@ class ScreenshotsModel extends BasicModel
return $count;
}
/* Get a random screenshot (an object and not a filename) .*/
public function getRandomScreenshot()
/**
* Get a random screenshot (an object and not a filename).
*/
public function getRandomScreenshot(): Screenshot
{
return ScreenshotQuery::create()->findRandom();
}
+7 -4
View File
@@ -9,20 +9,23 @@ use Symfony\Component\Yaml\Yaml;
*/
class SimpleYamlModel extends BasicModel
{
private $filename;
private $type;
private string $filename;
private string $type;
const FILE_NOT_FOUND = 'The filename %s could not be found';
const YAML_PARSE_FAILED = 'Unable to parse the contents of the file %s';
public function __construct($type, $filename)
public function __construct(string $type, string $filename)
{
parent::__construct();
$this->filename = $this->getLocalizedFile($filename);
$this->type = "ScummVM\Objects\\$type";
}
public function getAllData($assignIdsToArray = true)
/**
* @return array<string|int, mixed>
*/
public function getAllData(bool $assignIdsToArray = true) : array
{
$objects = $this->getFromCache();
if (is_null($objects)) {
+7 -2
View File
@@ -1,6 +1,7 @@
<?php
namespace ScummVM\Models;
use ScummVM\OrmObjects\Version;
use ScummVM\OrmObjects\VersionQuery;
/**
@@ -8,8 +9,12 @@ use ScummVM\OrmObjects\VersionQuery;
*/
class VersionsModel extends BasicModel
{
/* Get all versions from YAML */
public function getAllVersions()
/**
* Get all versions from YAML
*
* @return Version[]
*/
public function getAllVersions(): array
{
$data = $this->getFromCache();
if (is_null($data)) {
+13 -10
View File
@@ -7,13 +7,16 @@ namespace ScummVM\Objects;
*/
class Article extends BasicObject
{
private $url;
private $language;
private $source;
private $date;
private ?string $url;
private ?string $language;
private ?string $source;
private ?string $date;
/* Article object constructor. */
public function __construct($data)
/**
* Article object constructor.
* @param array{'url'?: string, 'language'?: string, 'source'?: string, 'date'?: string} $data
*/
public function __construct(array $data)
{
parent::__construct($data);
$this->url = $data['url'] ?? null;
@@ -23,25 +26,25 @@ class Article extends BasicObject
}
/* Get the URL. */
public function getURL()
public function getURL(): ?string
{
return $this->url;
}
/* Get the language. */
public function getLanguage()
public function getLanguage(): ?string
{
return $this->language;
}
/* Get the source that published it. */
public function getSource()
public function getSource(): ?string
{
return $this->source;
}
/* Get the date it was posted. */
public function getDate()
public function getDate(): ?string
{
return $this->date;
}
+12 -8
View File
@@ -7,27 +7,30 @@ namespace ScummVM\Objects;
*/
abstract class BasicObject
{
protected $name;
protected $description;
protected ?string $name;
protected ?string $description;
public function __construct($data)
/**
* @param array{'description'?: string, 'name'?: string} $data
*/
public function __construct(array $data)
{
$this->description = $data['description'] ?? null;
$this->name = $data['name'] ?? null;
}
public function __toString()
public function __toString(): string
{
return $this->getName() ?? '';
}
/* Get the name. */
public function getName()
public function getName(): ?string
{
return $this->name;
}
public function getDescription()
public function getDescription(): ?string
{
return $this->description;
}
@@ -36,9 +39,10 @@ abstract class BasicObject
* If the input array doesn't contain the numerical key 0, wrap it inside
* an array. This functions operates on the data directly.
*
* @param mixed $data the input
* @param $data the input
* @param-out mixed[] $data
*/
public function toArray(&$data)
public function toArray(mixed &$data): void
{
if (!is_array($data) || !array_key_exists(0, $data)) {
$data = array($data);
+16 -8
View File
@@ -9,11 +9,15 @@ namespace ScummVM\Objects;
*/
abstract class BasicSection extends BasicObject
{
protected $title;
protected $anchor;
protected $subsections;
protected string $title;
protected string $anchor;
/** @var array<static> */
protected array $subsections;
public function __construct($data)
/**
* @param array{'title': string, 'anchor': string, 'subsection'?: array<mixed>, ...} $data
*/
public function __construct(array $data)
{
parent::__construct($data);
$this->title = $data['title'];
@@ -28,19 +32,23 @@ abstract class BasicSection extends BasicObject
}
/* Get the title. */
public function getTitle()
public function getTitle(): string
{
return $this->title;
}
/* Get the anchor. */
public function getAnchor()
public function getAnchor(): string
{
return $this->anchor;
}
/* Get the optional list of subsections. */
public function getSubSections()
/**
* Get the optional list of subsections.
*
* @return array<static>
*/
public function getSubSections(): array
{
return $this->subsections;
}
+26 -8
View File
@@ -7,11 +7,21 @@ namespace ScummVM\Objects;
*/
class CreditsSection extends BasicSection
{
private $groups;
private $paragraphs;
/** @var array<array{'name': string, 'persons': array<Person>}> */
private array $groups;
/** @var string[] */
private array $paragraphs;
/* CreditsSection object constructor. */
public function __construct($data)
/**
* CreditsSection object constructor.
*
* @param array{'title': string, 'anchor': string, 'subsection'?: array<mixed>,
* 'group'?: array<array{
* 'person': array<array{'description'?: string, 'name'?: string, 'alias': string}>,
* 'name': string}>,
* 'paragraph'?: string[]} $data
*/
public function __construct(array $data)
{
parent::__construct($data);
$this->groups = [];
@@ -36,14 +46,22 @@ class CreditsSection extends BasicSection
}
}
/* Get the optional list of groups. */
public function getGroups()
/**
* Get the optional list of groups.
*
* @return array<array{'name': string, 'persons': array<Person>}>
*/
public function getGroups(): array
{
return $this->groups;
}
/* Get the optional list of paragraphs. */
public function getParagraphs()
/**
* Get the optional list of paragraphs.
*
* @return string[]
*/
public function getParagraphs(): array
{
return $this->paragraphs;
}
+30 -14
View File
@@ -1,6 +1,9 @@
<?php
namespace ScummVM\Objects;
use ScummVM\OrmObjects\Download;
use ScummVM\OrmObjects\GameDownload;
use Propel\Runtime\Map\TableMap;
/**
@@ -8,23 +11,24 @@ use Propel\Runtime\Map\TableMap;
*/
class DownloadsSection extends BasicSection
{
private $notes;
private $items;
private string $notes;
/** @var array<WebLink|File> */
private array $items;
/**
* __construct
*
* @param mixed $data [id, notes, anchor, title]
* @return void
* @param array{'title': string, 'anchor': string, 'subsection'?: array<mixed>, 'notes': string} $data
*/
public function __construct($data)
public function __construct(array $data)
{
parent::__construct($data);
$this->notes = $data['notes'];
$this->items = [];
}
public function addItem($item)
/**
* @param Download|GameDownload $item
*/
public function addItem(object $item): void
{
if ($item->getCategoryIcon()) {
$this->items[] = new File($item->toArray(TableMap::TYPE_FIELDNAME));
@@ -46,24 +50,36 @@ class DownloadsSection extends BasicSection
}
}
/* Get the optional notes. */
public function getNotes()
/**
* Get the optional notes.
*/
public function getNotes(): ?string
{
return $this->notes;
}
/* Get the list of items. */
public function getItems()
/**
* Get the list of items.
*
* @return array<WebLink|File>
*/
public function getItems(): array
{
return $this->items;
}
public function addSubsection($section)
/**
* @param static $section
*/
public function addSubsection(DownloadsSection $section): void
{
$this->subsections[$section->getAnchor()] = $section;
}
private function hasOldVersion($item)
/**
* @param Download|GameDownload $item
*/
private function hasOldVersion(object $item): bool
{
return method_exists($item, 'getVersion') && $item->getVersion() !== RELEASE && $item->getVersion() !== 'Daily';
}
+24 -14
View File
@@ -8,15 +8,21 @@ use ScummVM\FileUtils;
*/
class File extends BasicObject
{
private $autoId;
private $category;
private $category_icon;
private $url;
private $extra_info;
private $notes;
private $user_agent;
private $version;
private ?int $autoId;
private string $category;
private string $category_icon;
private string $url;
/** @var array{'size': string, 'sha256': string, 'ext': string, 'date': string}|array{} */
private array $extra_info;
private string $notes;
private string $user_agent;
private ?string $version;
/**
* @param array{'description'?: string, 'name'?: string, 'auto_id'?: int, 'category': string,
* 'category_icon': string, 'notes'?: string, 'user_agent'?: string, 'version'?: string,
* 'url': string|array{0: string, '@attributes': array<mixed>}} $data
*/
public function __construct($data)
{
parent::__construct($data);
@@ -64,30 +70,34 @@ class File extends BasicObject
}
/* Get the category icon. */
public function getCategoryIcon()
public function getCategoryIcon(): string
{
return $this->category_icon;
}
/* Get the URL. */
public function getURL()
public function getURL(): string
{
return $this->url;
}
/* Get the extra information. */
public function getExtraInfo()
/**
* Get the extra information.
*
* @return array{'size': string, 'sha256': string, 'ext': string, 'date': string}|array{}
*/
public function getExtraInfo(): array
{
return $this->extra_info;
}
public function getNotes()
public function getNotes(): string
{
return $this->notes;
}
/* Get the user-agent. */
public function getUserAgent()
public function getUserAgent(): string
{
return $this->user_agent;
}
+15 -6
View File
@@ -7,10 +7,15 @@ namespace ScummVM\Objects;
class MenuItem extends BasicObject
{
private $class;
private $entries;
private string $class;
/** @var array<string, string> */
private array $entries;
/* Menu object constructor. */
/**
* Menu object constructor.
* @param array{'description'?: string, 'name'?: string, 'class': string,
* 'links': array<array{'name': string, 'href': string}>} $data
*/
public function __construct($data)
{
parent::__construct($data);
@@ -22,13 +27,17 @@ class MenuItem extends BasicObject
}
/* Get the CSS class. */
public function getClass()
public function getClass(): string
{
return $this->class;
}
/* Get the list of links, with the name as key and URL as value. */
public function getEntries()
/**
* Get the list of links, with the name as key and URL as value.
*
* @return array<string, string>
*/
public function getEntries(): array
{
return $this->entries;
}
+14 -14
View File
@@ -10,16 +10,16 @@ use Erusev\Parsedown;
*/
class News
{
private $title;
private $date;
private $author;
private $content;
private $filename;
private string $title;
private string $date;
private string $author;
private string $content;
private string $filename;
/**
* News object constructor that extracts the data from the YAML frontmatter.
*/
public function __construct($data, $filename, $processContent = false)
public function __construct(string $data, string $filename, bool $processContent = false)
{
$object = YamlFrontMatter::parse($data);
$Parsedown = new \Parsedown();
@@ -42,12 +42,12 @@ class News
* http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
* for a list of valid entities for both XML and HTML
*/
public function processText($text)
public function processText(string $text): string
{
return html_entity_decode($text, ENT_COMPAT, 'UTF-8');
}
private function localizeLinks($body)
private function localizeLinks(string $body): string
{
global $lang;
if ($lang == DEFAULT_LOCALE || !$lang) {
@@ -70,37 +70,37 @@ class News
}
/* Get the title. */
public function getTitle()
public function getTitle(): string
{
return $this->title;
}
/* Get the date. */
public function getDate()
public function getDate(): string
{
return $this->date;
}
/* Get the author. */
public function getAuthor()
public function getAuthor(): string
{
return $this->author;
}
/* Get the content. */
public function getContent()
public function getContent(): string
{
return $this->content;
}
/* Get the filename. */
public function getFilename()
public function getFilename(): string
{
return $this->filename;
}
/* Get the News link. */
public function getLink()
public function getLink(): string
{
return URL_BASE . 'news/' . substr($this->filename, 0, -9);
}
+6 -3
View File
@@ -7,9 +7,12 @@ namespace ScummVM\Objects;
*/
class Person extends BasicObject
{
private $alias;
private string $alias;
/* Person object constructor. */
/**
* Person object constructor.
* @param array{'description'?: string, 'name'?: string, 'alias': string} $data
*/
public function __construct($data)
{
parent::__construct($data);
@@ -17,7 +20,7 @@ class Person extends BasicObject
}
/* Get the alias. */
public function getAlias()
public function getAlias(): string
{
return $this->alias;
}
+9 -6
View File
@@ -2,15 +2,18 @@
namespace ScummVM\Objects;
/**
* The article class represents a link on the website to an article covering
* The sponsor class represents a link on the website to a sponsor and its logo and supporting
* ScummVM in some way.
*/
class Sponsor extends BasicObject
{
private $link;
private $image;
private string $link;
private string $image;
/* Article object constructor. */
/**
* Sponsor object constructor.
* @param array{'description'?: string, 'name'?: string, 'link': string, 'image': string} $data
*/
public function __construct($data)
{
parent::__construct($data);
@@ -19,13 +22,13 @@ class Sponsor extends BasicObject
}
/* Get the sponsor link. */
public function getLink()
public function getLink(): string
{
return $this->link;
}
/* Get the sponsor image */
public function getImage()
public function getImage(): string
{
return $this->image;
}
+9 -6
View File
@@ -6,10 +6,13 @@ namespace ScummVM\Objects;
*/
class WebLink extends BasicObject
{
private $notes;
private $url;
private string $notes;
private string $url;
/* WebLink object constructor. */
/**
* WebLink object constructor.
* @param array{'description'?: string, 'name'?: string, 'notes': string, 'url': string} $data
*/
public function __construct($data)
{
parent::__construct($data);
@@ -17,19 +20,19 @@ class WebLink extends BasicObject
$this->url = $data['url'];
}
public function getNotes()
public function getNotes(): string
{
return $this->notes;
}
/* Get the URL of the link. */
public function getURL()
public function getURL(): string
{
return $this->url;
}
/* Get the user-agent. */
public function getUserAgent()
public function getUserAgent(): string
{
return "";
}
+3 -3
View File
@@ -15,7 +15,7 @@ use ScummVM\OrmObjects\Base\Compatibility as BaseCompatibility;
*/
class Compatibility extends BaseCompatibility
{
private function processPlatforms($values)
private function processPlatforms(string $values): string
{
$platforms = \explode(",", $values);
@@ -27,7 +27,7 @@ class Compatibility extends BaseCompatibility
return $retVal;
}
public function getScummVmId($version)
public function getScummVmId(string $version): string
{
$gameId = $this->getGame()->getId();
if ($version == "DEV" || version_compare($version, "2.2.0") > 0) {
@@ -39,7 +39,7 @@ class Compatibility extends BaseCompatibility
}
}
public function getNotes()
public function getNotes(): string
{
$notes = "### Support Level\n\n";
$notes .= "[[support_description]]\n\n";
+2 -2
View File
@@ -15,7 +15,7 @@ use ScummVM\OrmObjects\Base\Demo as BaseDemo;
*/
class Demo extends BaseDemo
{
public function getName()
public function getName(): string
{
$gameName = $this->getGame()->getName();
$platformName = $this->getPlatform()->getName();
@@ -23,7 +23,7 @@ class Demo extends BaseDemo
return "$gameName ($platformName $category Demo)";
}
public function __toString()
public function __toString(): string
{
return $this->getName();
}
+17 -8
View File
@@ -15,9 +15,15 @@ use ScummVM\OrmObjects\Base\Screenshot as BaseScreenshot;
*/
class Screenshot extends BaseScreenshot
{
private $files;
/**
* @var array<array{'filename': string, 'caption': string, 'url': string}>
*/
private array $files;
public function getFiles()
/**
* @return array<array{'filename': string, 'caption': string, 'url': string}>
*/
public function getFiles(): array
{
if (!isset($this->files)) {
$this->files = [];
@@ -37,7 +43,10 @@ class Screenshot extends BaseScreenshot
return $this->files;
}
public function addFiles($files)
/**
* @param array<array{'filename': string, 'caption': string, 'url': string}> $files
*/
public function addFiles(array $files): void
{
if (isset($this->files)) {
$this->files = array_merge($this->files, $files);
@@ -46,7 +55,7 @@ class Screenshot extends BaseScreenshot
}
}
public function getCategory()
public function getCategory(): string
{
$series = $this->getGame()->getSeries();
if ($series) {
@@ -57,7 +66,7 @@ class Screenshot extends BaseScreenshot
}
}
public function getName()
public function getName(): string
{
$series = $this->getGame()->getSeries();
if ($series) {
@@ -67,7 +76,7 @@ class Screenshot extends BaseScreenshot
}
}
public function getCaption()
public function getCaption(): string
{
$name = $this->getGame()->getName();
$extras = [];
@@ -90,7 +99,7 @@ class Screenshot extends BaseScreenshot
return htmlspecialchars($name);
}
public function getFileMask()
public function getFileMask(): string
{
// Remove engine prefix
$game_short_id = substr($this->getGame()->getId(), strpos($this->getGame()->getId(), ':') + 1);
@@ -106,7 +115,7 @@ class Screenshot extends BaseScreenshot
return $mask;
}
public function __toString()
public function __toString(): string
{
return $this->getCaption();
}
+7 -3
View File
@@ -21,7 +21,7 @@ use ScummVM\OrmObjects\Map\ScreenshotTableMap;
*/
class ScreenshotQuery extends BaseScreenshotQuery
{
public function findRandom(ConnectionInterface $con = null)
public function findRandom(ConnectionInterface $con = null): ChildScreenshot
{
if ($con === null) {
$con = Propel::getServiceContainer()->getReadConnection(ScreenshotTableMap::DATABASE_NAME);
@@ -48,7 +48,11 @@ class ScreenshotQuery extends BaseScreenshotQuery
return $obj;
}
public function findCategories(ConnectionInterface $con = null)
/**
* @return array<array{'category_key': string, 'category_name': string, 'subcategory_key': string,
* 'subcategory_name': string}>
*/
public function findCategories(ConnectionInterface $con = null): array
{
if ($con === null) {
$con = Propel::getServiceContainer()->getReadConnection(ScreenshotTableMap::DATABASE_NAME);
@@ -99,7 +103,7 @@ class ScreenshotQuery extends BaseScreenshotQuery
return $obj;
}
public function filterByCompanyId($companyId, ConnectionInterface $con = null)
public function filterByCompanyId(string $companyId, ConnectionInterface $con = null): self
{
if ($companyId !== 'other') {
return $this->useGameQuery()
+8 -3
View File
@@ -2,6 +2,7 @@
namespace ScummVM\Pages;
use ScummVM\Controller;
use Spatie\YamlFrontMatter\Document;
use Spatie\YamlFrontMatter\YamlFrontMatter;
use Erusev\Parsedown;
@@ -17,7 +18,7 @@ class ArticlePage extends Controller
$this->template = 'pages/article.tpl';
}
private function getArticle($filename)
private function getArticle(string $filename): Document
{
global $lang;
if (!$lang) {
@@ -36,8 +37,12 @@ class ArticlePage extends Controller
return YamlFrontMatter::parse(file_get_contents($fname));
}
/* Display the index page. */
public function index($params)
/**
* Display the index page.
*
* @param array{'article'?: string} $params
*/
public function index(array $params): void
{
if (empty($params['article'])) {
throw new \ErrorException(self::ARTICLE_NAME_MISSING);
+21 -8
View File
@@ -12,10 +12,16 @@ use ScummVM\OrmObjects\VersionQuery;
*/
class CompatibilityPage extends Controller
{
private $supportLevel;
private $supportLevelDescriptions;
private $supportLevelClass;
private $compatibilityModel;
// Would be useful for PHPStan
//private const LEVELS = ['untested', 'broken', 'bugged', 'good', 'excellent'];
/** @var array<value-of<self::LEVELS>, ?string> */
private array $supportLevel;
/** @var array<value-of<self::LEVELS>, ?string> */
private array $supportLevelDescriptions;
/** @var array<value-of<self::LEVELS>, ?string> */
private array $supportLevelClass;
private CompatibilityModel $compatibilityModel;
/* Constructor. */
public function __construct()
@@ -49,8 +55,12 @@ class CompatibilityPage extends Controller
$this->compatibilityModel = new CompatibilityModel();
}
/* Display the index page. */
public function index($args)
/**
* Display the index page.
*
* @param array{'version'?: string, 'game'?: string} $args
*/
public function index($args): void
{
$version = $args['version'] ?? null;
$target = $args['game'] ?? null;
@@ -75,7 +85,7 @@ class CompatibilityPage extends Controller
}
/* We should show detailed information for a specific target. */
public function getGame($target, $version)
public function getGame(string $target, string $version): void
{
$game = $this->compatibilityModel->getGameData($version, $target);
// Redirect to main compatibility page if the requested game doesn't exist
@@ -107,7 +117,10 @@ class CompatibilityPage extends Controller
}
/* We should show all the compatibility stats for a specific version. */
public function getAll($version, $versions)
/**
* @param string[] $versions
*/
public function getAll(string $version, array $versions): void
{
$compat_data = $this->compatibilityModel->getAllDataGroups($version);
+2 -2
View File
@@ -6,7 +6,7 @@ use ScummVM\Models\GameDemosModel;
class DemosPage extends Controller
{
private $gameDemosModel;
private GameDemosModel $gameDemosModel;
/* Constructor. */
public function __construct()
@@ -17,7 +17,7 @@ class DemosPage extends Controller
}
/* Display the index page. */
public function index()
public function index(): void
{
$demos = $this->gameDemosModel->getAllGroupsAndDemos();
$this->renderPage(
+2 -2
View File
@@ -6,7 +6,7 @@ use ScummVM\Models\DirectorDemosModel;
class DirectorDemosPage extends Controller
{
private $gameDemosModel;
private DirectorDemosModel $gameDemosModel;
/* Constructor. */
public function __construct()
@@ -17,7 +17,7 @@ class DirectorDemosPage extends Controller
}
/* Display the index page. */
public function index()
public function index(): void
{
$demos = $this->gameDemosModel->getAllGroupsAndDemos();
$this->renderPage(
+2 -2
View File
@@ -6,7 +6,7 @@ use ScummVM\Models\DownloadsModel;
class DownloadsPage extends Controller
{
private $downloadsModel;
private DownloadsModel $downloadsModel;
/* Constructor. */
public function __construct()
{
@@ -16,7 +16,7 @@ class DownloadsPage extends Controller
}
/* Display the index page. */
public function index()
public function index(): void
{
$downloads = $this->downloadsModel->getAllDownloads();
$recommendedDownload = $this->downloadsModel->getRecommendedDownload();
+9 -5
View File
@@ -6,9 +6,9 @@ use ScummVM\Models\NewsModel;
class FeedsPage extends Controller
{
private $template_rss;
private $template_atom;
private $newsModel;
private string $template_rss;
private string $template_atom;
private NewsModel $newsModel;
/* Constructor. */
public function __construct()
@@ -19,8 +19,12 @@ class FeedsPage extends Controller
$this->newsModel = new NewsModel();
}
/* Display the index page. */
public function index($args)
/**
* Display the index page.
*
* @param array{'type'?: string} $args
*/
public function index(array $args): void
{
$feed = isset($args['type']) ? $args['type'] : '';
if ($feed == 'atom') {
+2 -2
View File
@@ -6,7 +6,7 @@ use ScummVM\Models\GameDownloadsModel;
class GamesPage extends Controller
{
private $gameDownloadsModel;
private GameDownloadsModel $gameDownloadsModel;
/* Constructor. */
public function __construct()
@@ -17,7 +17,7 @@ class GamesPage extends Controller
}
/* Display the index page. */
public function index()
public function index(): void
{
$downloads = $this->gameDownloadsModel->getAllDownloads();
$this->renderPage(
+2 -2
View File
@@ -7,7 +7,7 @@ use ScummVM\Models\LinksModel;
class LinksPage extends Controller
{
private $linksModel;
private LinksModel $linksModel;
/* Constructor. */
public function __construct()
@@ -18,7 +18,7 @@ class LinksPage extends Controller
}
/* Display the index page. */
public function index()
public function index(): void
{
$links = $this->linksModel->getAllGroupsAndLinks();
$this->renderPage(
+10 -6
View File
@@ -7,8 +7,8 @@ use ScummVM\Models\ScreenshotsModel;
class NewsPage extends Controller
{
private $newsModel;
private $screenshotModels;
private NewsModel $newsModel;
private ScreenshotsModel $screenshotModels;
/* Constructor. */
public function __construct()
@@ -19,8 +19,12 @@ class NewsPage extends Controller
$this->screenshotModels = new ScreenshotsModel();
}
/* Display the index page. */
public function index($args)
/**
* Display the index page.
*
* @param array{'date'?: string} $args
*/
public function index(array $args): void
{
$filename = $args['date'] ?? null;
@@ -36,7 +40,7 @@ class NewsPage extends Controller
}
/* Display a specific news item, or all news items. */
public function getNews($filename = null)
public function getNews(?string $filename = null): void
{
if ($filename == null) {
$news_items = $this->newsModel->getAllNews();
@@ -62,7 +66,7 @@ class NewsPage extends Controller
}
/* Display the main page with limited news items and intro text. */
public function getNewsIntro()
public function getNewsIntro(): void
{
$news_items = $this->newsModel->getLatestNews(NEWS_ITEMS);
$random_shot = $this->screenshotModels->getRandomScreenshot();
+8 -4
View File
@@ -6,7 +6,7 @@ use ScummVM\Models\ScreenshotsModel;
class ScreenshotsPage extends Controller
{
private $screenshotsModel;
private ScreenshotsModel $screenshotsModel;
/* Constructor. */
public function __construct()
@@ -15,8 +15,12 @@ class ScreenshotsPage extends Controller
$this->screenshotsModel = new ScreenshotsModel();
}
/* Display the index page. */
public function index($args)
/**
* Display the index page.
*
* @param array{'category'?: string, 'game'?: string} $args
*/
public function index(array $args): void
{
$category = $args['category'] ?? null;
$game = $args['game'] ?? null;
@@ -49,7 +53,7 @@ class ScreenshotsPage extends Controller
}
/* Display the selected category. */
public function getCategory($category, $game)
public function getCategory(string $category, ?string $game): void
{
if (empty($game)) {
$screenshots = $this->screenshotsModel->getScreenshotsByCompanyId($category);
+5 -4
View File
@@ -2,6 +2,7 @@
namespace ScummVM\Pages;
use ScummVM\Controller;
use ScummVM\Models\BasicModel;
use ScummVM\Models\SimpleYamlModel;
class SimplePage extends Controller
@@ -14,11 +15,11 @@ class SimplePage extends Controller
'credits' => ['CreditsSection', 'credits.yaml'],
];
private $model;
private $key;
private SimpleYamlModel $model;
private string $key;
/* Constructor. */
public function __construct($key)
public function __construct(string $key)
{
parent::__construct();
$this->template = "pages/$key.tpl";
@@ -34,7 +35,7 @@ class SimplePage extends Controller
}
/* Display the index page. */
public function index($data = null)
public function index(mixed $data = null): void
{
if (isset($this->model)) {
$data = $this->model->getAllData();
+3 -3
View File
@@ -6,9 +6,9 @@ use ScummVM\Controller;
class StaticPage extends Controller
{
const FILE_NOT_FOUND = 'The filename %s could not be found';
private $filename;
private string $filename;
public function __construct($key)
public function __construct(string $key)
{
parent::__construct();
@@ -19,7 +19,7 @@ class StaticPage extends Controller
}
/* Display the index page. */
public function index($data = null)
public function index(): void
{
readfile($this->filename);
}
+1 -1
View File
@@ -3,7 +3,7 @@ namespace ScummVM;
class SiteUtils
{
public static function localizePath($path, $checkStaticFiles = false)
public static function localizePath(string $path, bool $checkStaticFiles = false): string
{
global $lang;
// No lang needed