[core] a load more type hints, and fix bugs revealed by type hints

This commit is contained in:
Shish 2024-01-20 14:10:59 +00:00
parent 373be4e05c
commit b60c3fe362
158 changed files with 1532 additions and 616 deletions

View file

@ -496,6 +496,9 @@ class BasePage
return ["script.js"];
}
/**
* @return array{0: NavLink[], 1: NavLink[]}
*/
protected function get_nav_links(): array
{
$pnbe = send_event(new PageNavBuildingEvent());
@ -641,6 +644,7 @@ class BasePage
class PageNavBuildingEvent extends Event
{
/** @var NavLink[] */
public array $links = [];
public function add_nav_link(string $name, Link $link, string $desc, ?bool $active = null, int $order = 50): void
@ -653,6 +657,7 @@ class PageSubNavBuildingEvent extends Event
{
public string $parent;
/** @var NavLink[] */
public array $links = [];
public function __construct(string $parent)
@ -704,6 +709,9 @@ class NavLink
}
}
/**
* @param string[] $pages_matched
*/
public static function is_active(array $pages_matched, string $url = null): bool
{
/**

View file

@ -67,6 +67,11 @@ class EventTracingCache implements CacheInterface
return $val;
}
/**
* @param string[] $keys
* @param mixed $default
* @return mixed[]
*/
public function getMultiple($keys, $default = null)
{
$this->tracer->begin("Cache Get Multiple", ["keys" => $keys]);
@ -75,6 +80,9 @@ class EventTracingCache implements CacheInterface
return $val;
}
/**
* @param array<string, mixed> $values
*/
public function setMultiple($values, $ttl = null)
{
$this->tracer->begin("Cache Set Multiple", ["keys" => array_keys($values)]);
@ -83,6 +91,9 @@ class EventTracingCache implements CacheInterface
return $val;
}
/**
* @param string[] $keys
*/
public function deleteMultiple($keys)
{
$this->tracer->begin("Cache Delete Multiple", ["keys" => $keys]);

View file

@ -10,7 +10,9 @@ namespace Shimmie2;
class CommandBuilder
{
private string $executable;
/** @var string[] */
private array $args = [];
/** @var string[] */
public array $output;
public function __construct(string $executable)

View file

@ -41,6 +41,8 @@ interface Config
/**
* Set a configuration option to a new value, regardless of what the value is at the moment.
*
* @param mixed[] $value
*/
public function set_array(string $name, array $value): void;
//@} /*--------------------------------------------------------------------------------------------*/
@ -93,6 +95,8 @@ interface Config
* This has the advantage that the values will show up in the "advanced" setup
* page where they can be modified, while calling get_* with a "default"
* parameter won't show up.
*
* @param mixed[] $value
*/
public function set_default_array(string $name, array $value): void;
//@} /*--------------------------------------------------------------------------------------------*/
@ -120,6 +124,9 @@ interface Config
/**
* Pick a value out of the table by name, cast to the appropriate data type.
*
* @param mixed[] $default
* @return mixed[]
*/
public function get_array(string $name, ?array $default = []): ?array;
//@} /*--------------------------------------------------------------------------------------------*/
@ -134,6 +141,7 @@ interface Config
*/
abstract class BaseConfig implements Config
{
/** @var array<string, mixed> */
public array $values = [];
public function set_int(string $name, ?int $value): void
@ -205,16 +213,31 @@ abstract class BaseConfig implements Config
}
}
/**
* @template T of int|null
* @param T $default
* @return T|int
*/
public function get_int(string $name, ?int $default = null): ?int
{
return (int)($this->get($name, $default));
}
/**
* @template T of float|null
* @param T $default
* @return T|float
*/
public function get_float(string $name, ?float $default = null): ?float
{
return (float)($this->get($name, $default));
}
/**
* @template T of string|null
* @param T $default
* @return T|string
*/
public function get_string(string $name, ?string $default = null): ?string
{
$val = $this->get($name, $default);
@ -224,17 +247,34 @@ abstract class BaseConfig implements Config
return $val;
}
/**
* @template T of bool|null
* @param T $default
* @return T|bool
*/
public function get_bool(string $name, ?bool $default = null): ?bool
{
return bool_escape($this->get($name, $default));
}
public function get_array(string $name, ?array $default = []): ?array
/**
* @template T of array<string>|null
* @param T $default
* @return T|array<string>
*/
public function get_array(string $name, ?array $default = null): ?array
{
return explode(",", $this->get($name, ""));
$val = $this->get($name);
if(is_null($val)) {
return $default;
}
if(empty($val)) {
return [];
}
return explode(",", $val);
}
private function get(string $name, $default = null): mixed
private function get(string $name, mixed $default = null): mixed
{
if (isset($this->values[$name])) {
return $this->values[$name];

View file

@ -19,8 +19,12 @@ enum DatabaseDriverID: string
class DatabaseException extends SCoreException
{
public string $query;
/** @var array<string, mixed> */
public array $args;
/**
* @param array<string, mixed> $args
*/
public function __construct(string $msg, string $query, array $args)
{
parent::__construct($msg);
@ -32,6 +36,8 @@ class DatabaseException extends SCoreException
/**
* A class for controlled database access
*
* @phpstan-type QueryArgs array<string, string|int|bool|null>
*/
class Database
{
@ -52,6 +58,7 @@ class Database
* How many queries this DB object has run
*/
public int $query_count = 0;
/** @var string[] */
public array $queries = [];
public function __construct(string $dsn)
@ -162,13 +169,15 @@ class Database
return $this->get_engine()->get_version($this->get_db());
}
/**
* @param QueryArgs $args
*/
private function count_time(string $method, float $start, string $query, ?array $args): void
{
global $_tracer, $tracer_enabled;
$dur = ftime() - $start;
// trim whitespace
$query = preg_replace('/[\n\t ]/m', ' ', $query);
$query = preg_replace('/ +/m', ' ', $query);
$query = preg_replace('/[\n\t ]+/m', ' ', $query);
$query = trim($query);
if ($tracer_enabled) {
$_tracer->complete($start * 1000000, $dur * 1000000, "DB Query", ["query" => $query, "args" => $args, "method" => $method]);
@ -188,6 +197,9 @@ class Database
$this->get_engine()->notify($this->get_db(), $channel, $data);
}
/**
* @param QueryArgs $args
*/
public function _execute(string $query, array $args = []): PDOStatement
{
try {
@ -203,6 +215,8 @@ class Database
/**
* Execute an SQL query with no return
*
* @param QueryArgs $args
*/
public function execute(string $query, array $args = []): PDOStatement
{
@ -214,6 +228,9 @@ class Database
/**
* Execute an SQL query and return a 2D array.
*
* @param QueryArgs $args
* @return array<array<string, mixed>>
*/
public function get_all(string $query, array $args = []): array
{
@ -225,6 +242,8 @@ class Database
/**
* Execute an SQL query and return a iterable object for use with generators.
*
* @param QueryArgs $args
*/
public function get_all_iterable(string $query, array $args = []): PDOStatement
{
@ -236,6 +255,9 @@ class Database
/**
* Execute an SQL query and return a single row.
*
* @param QueryArgs $args
* @return array<string, mixed>
*/
public function get_row(string $query, array $args = []): ?array
{
@ -247,6 +269,9 @@ class Database
/**
* Execute an SQL query and return the first column of each row.
*
* @param QueryArgs $args
* @return array<mixed>
*/
public function get_col(string $query, array $args = []): array
{
@ -258,6 +283,8 @@ class Database
/**
* Execute an SQL query and return the first column of each row as a single iterable object.
*
* @param QueryArgs $args
*/
public function get_col_iterable(string $query, array $args = []): \Generator
{
@ -271,6 +298,9 @@ class Database
/**
* Execute an SQL query and return the the first column => the second column.
*
* @param QueryArgs $args
* @return array<string, mixed>
*/
public function get_pairs(string $query, array $args = []): array
{
@ -283,6 +313,8 @@ class Database
/**
* Execute an SQL query and return the the first column => the second column as an iterable object.
*
* @param QueryArgs $args
*/
public function get_pairs_iterable(string $query, array $args = []): \Generator
{
@ -296,6 +328,8 @@ class Database
/**
* Execute an SQL query and return a single value, or null.
*
* @param QueryArgs $args
*/
public function get_one(string $query, array $args = []): mixed
{
@ -307,6 +341,8 @@ class Database
/**
* Execute an SQL query and returns a bool indicating if any data was returned
*
* @param QueryArgs $args
*/
public function exists(string $query, array $args = []): bool
{

View file

@ -129,7 +129,7 @@ class PostgreSQL extends DBEngine
}
// shimmie functions for export to sqlite
function _unix_timestamp($date): int
function _unix_timestamp(string $date): int
{
return strtotime($date);
}
@ -137,11 +137,11 @@ function _now(): string
{
return date("Y-m-d H:i:s");
}
function _floor($a): float
function _floor(float|int $a): float
{
return floor($a);
}
function _log($a, $b = null): float
function _log(float $a, ?float $b = null): float
{
if (is_null($b)) {
return log($a);
@ -149,19 +149,19 @@ function _log($a, $b = null): float
return log($b, $a);
}
}
function _isnull($a): bool
function _isnull(mixed $a): bool
{
return is_null($a);
}
function _md5($a): string
function _md5(string $a): string
{
return md5($a);
}
function _concat($a, $b): string
function _concat(string $a, string $b): string
{
return $a . $b;
}
function _lower($a): string
function _lower(string $a): string
{
return strtolower($a);
}
@ -169,7 +169,7 @@ function _rand(): int
{
return rand();
}
function _ln($n): float
function _ln(float $n): float
{
return log($n);
}

View file

@ -143,6 +143,9 @@ class PageRequestEvent extends Event
* Many things use these functions
*/
/**
* @return string[]
*/
public function get_search_terms(): array
{
$search_terms = [];
@ -172,7 +175,6 @@ class PageRequestEvent extends Event
$str = $out;
// end legacy
$search_terms = Tag::explode($str);
}
return $search_terms;

View file

@ -22,9 +22,10 @@ abstract class Extension
protected Themelet $theme;
public ExtensionInfo $info;
/** @var string[] */
private static array $enabled_extensions = [];
public function __construct($class = null)
public function __construct(?string $class = null)
{
$class = $class ?? get_called_class();
$this->theme = $this->get_theme_object($class);
@ -87,6 +88,9 @@ abstract class Extension
return in_array($key, self::$enabled_extensions);
}
/**
* @return string[]
*/
public static function get_enabled_extensions(): array
{
return self::$enabled_extensions;
@ -141,8 +145,11 @@ abstract class ExtensionInfo
public string $name;
public string $license;
public string $description;
/** @var array<string, string> */
public array $authors = [];
/** @var string[] */
public array $dependencies = [];
/** @var string[] */
public array $conflicts = [];
public ExtensionVisibility $visibility = ExtensionVisibility::DEFAULT;
public ?string $link = null;
@ -170,8 +177,11 @@ abstract class ExtensionInfo
return $this->support_info;
}
/** @var array<string, ExtensionInfo> */
private static array $all_info_by_key = [];
/** @var array<string, ExtensionInfo> */
private static array $all_info_by_class = [];
/** @var string[] */
private static array $core_extensions = [];
protected function __construct()
@ -207,16 +217,25 @@ abstract class ExtensionInfo
$this->supported = empty($this->support_info);
}
/**
* @return ExtensionInfo[]
*/
public static function get_all(): array
{
return array_values(self::$all_info_by_key);
}
/**
* @return string[]
*/
public static function get_all_keys(): array
{
return array_keys(self::$all_info_by_key);
}
/**
* @return string[]
*/
public static function get_core_extensions(): array
{
return self::$core_extensions;
@ -285,6 +304,7 @@ abstract class FormatterExtension extends Extension
*/
abstract class DataHandlerExtension extends Extension
{
/** @var string[] */
protected array $SUPPORTED_MIME = [];
public function onDataUpload(DataUploadEvent $event): void
@ -396,6 +416,9 @@ abstract class DataHandlerExtension extends Extension
return MimeType::matches_array($mime, $this->SUPPORTED_MIME);
}
/**
* @return string[]
*/
public static function get_all_supported_mimes(): array
{
$arr = [];
@ -413,6 +436,9 @@ abstract class DataHandlerExtension extends Extension
return $arr;
}
/**
* @return string[]
*/
public static function get_all_supported_exts(): array
{
$arr = [];

View file

@ -63,7 +63,9 @@ class ImageReplaceEvent extends Event
) {
parent::__construct();
$this->old_hash = $image->hash;
$this->new_hash = md5_file($tmp_filename);
$hash = md5_file($tmp_filename);
assert($hash !== false, "Failed to hash file $tmp_filename");
$this->new_hash = $hash;
}
}

View file

@ -23,6 +23,8 @@ enum ImagePropType
* As of 2.2, this no longer necessarily represents an
* image per se, but could be a video, sound file, or any
* other supported upload type.
*
* @implements \ArrayAccess<string, mixed>
*/
#[Type(name: "Post")]
class Image implements \ArrayAccess
@ -71,6 +73,8 @@ class Image implements \ArrayAccess
/**
* One will very rarely construct an image directly, more common
* would be to use Image::by_id, Image::by_hash, etc.
*
* @param array<string|int, mixed>|null $row
*/
public function __construct(?array $row = null)
{
@ -82,6 +86,7 @@ class Image implements \ArrayAccess
continue;
} elseif(property_exists($this, $name)) {
$t = (new \ReflectionProperty($this, $name))->getType();
assert(!is_null($t));
if(is_a($t, \ReflectionNamedType::class)) {
$this->$name = match($t->getName()) {
"int" => is_null($value) ? $value : int_escape((string)$value),
@ -116,10 +121,12 @@ class Image implements \ArrayAccess
public function offsetExists(mixed $offset): bool
{
assert(is_string($offset));
return array_key_exists($offset, static::$prop_types);
}
public function offsetGet(mixed $offset): mixed
{
assert(is_string($offset));
if(!$this->offsetExists($offset)) {
throw new \OutOfBoundsException("Undefined dynamic property: $offset");
}
@ -127,16 +134,19 @@ class Image implements \ArrayAccess
}
public function offsetSet(mixed $offset, mixed $value): void
{
assert(is_string($offset));
$this->dynamic_props[$offset] = $value;
}
public function offsetUnset(mixed $offset): void
{
assert(is_string($offset));
unset($this->dynamic_props[$offset]);
}
#[Field(name: "post_id")]
public function graphql_oid(): int
{
assert(!is_null($this->id));
return $this->id;
}
#[Field(name: "id")]
@ -170,6 +180,9 @@ class Image implements \ArrayAccess
return (is_numberish($id) && strlen($id) != 32) ? Image::by_id((int)$id) : Image::by_hash($id);
}
/**
* @param string[] $tags
*/
public static function by_random(array $tags = [], int $limit_range = 0): ?Image
{
$max = Search::count_images($tags);
@ -234,7 +247,9 @@ class Image implements \ArrayAccess
#[Field(name: "owner")]
public function get_owner(): User
{
return User::by_id($this->owner_id);
$user = User::by_id($this->owner_id);
assert(!is_null($user));
return $user;
}
/**
@ -457,7 +472,7 @@ class Image implements \ArrayAccess
* Get the image's mime type.
*/
#[Field(name: "mime")]
public function get_mime(): ?string
public function get_mime(): string
{
if ($this->mime === MimeType::WEBP && $this->lossless) {
return MimeType::WEBP_LOSSLESS;
@ -468,7 +483,7 @@ class Image implements \ArrayAccess
/**
* Set the image's mime type.
*/
public function set_mime($mime): void
public function set_mime(string $mime): void
{
$this->mime = $mime;
$ext = FileExtension::get_for_mime($this->get_mime());
@ -545,6 +560,8 @@ class Image implements \ArrayAccess
/**
* Set the tags for this image.
*
* @param string[] $unfiltered_tags
*/
public function set_tags(array $unfiltered_tags): void
{

View file

@ -12,9 +12,10 @@ namespace Shimmie2;
* Add a directory full of images
*
* @param string $base
* @param string[] $extra_tags
* @return UploadResult[]
*/
function add_dir(string $base, ?array $extra_tags = []): array
function add_dir(string $base, array $extra_tags = []): array
{
global $database;
$results = [];
@ -33,6 +34,7 @@ function add_dir(string $base, ?array $extra_tags = []): array
]));
$results = [];
foreach($dae->images as $image) {
assert(!is_null($image->id));
$results[] = new UploadSuccess($filename, $image->id);
}
return $results;
@ -59,7 +61,7 @@ function get_file_ext(string $filename): ?string
* @param int $orig_width
* @param int $orig_height
* @param bool $use_dpi_scaling Enables the High-DPI scaling.
* @return array
* @return array{0: int, 1: int}
*/
function get_thumbnail_size(int $orig_width, int $orig_height, bool $use_dpi_scaling = false): array
{
@ -107,6 +109,9 @@ function get_thumbnail_size(int $orig_width, int $orig_height, bool $use_dpi_sca
}
}
/**
* @return array{0: int, 1: int, 2: float}
*/
function get_scaled_by_aspect_ratio(int $original_width, int $original_height, int $max_width, int $max_height): array
{
$xscale = ($max_width / $original_width);
@ -120,7 +125,7 @@ function get_scaled_by_aspect_ratio(int $original_width, int $original_height, i
/**
* Fetches the thumbnails height and width settings and applies the High-DPI scaling setting before returning the dimensions.
*
* @return array [width, height]
* @return array{0: int, 1: int}
*/
function get_thumbnail_max_size_scaled(): array
{
@ -147,7 +152,9 @@ function create_image_thumb(Image $image, string $engine = null): void
}
/**
* @param array{0: int, 1: int} $tsize
*/
function create_scaled_image(
string $inname,
string $outname,

View file

@ -86,7 +86,8 @@ class TagUsage
*/
class Tag
{
private static $tag_id_cache = [];
/** @var array<string, int> */
private static array $tag_id_cache = [];
public static function get_or_create_id(string $tag): int
{
@ -196,9 +197,13 @@ class Tag
public static function sanitize(string $tag): string
{
$tag = preg_replace("/\s/", "", $tag); # whitespace
assert($tag !== null);
$tag = preg_replace('/\x20[\x0e\x0f]/', '', $tag); # unicode RTL
assert($tag !== null);
$tag = preg_replace("/\.+/", ".", $tag); # strings of dots?
assert($tag !== null);
$tag = preg_replace("/^(\.+[\/\\\\])+/", "", $tag); # trailing slashes?
assert($tag !== null);
$tag = trim($tag, ", \t\n\r\0\x0B");
if ($tag == ".") {
@ -211,6 +216,10 @@ class Tag
return $tag;
}
/**
* @param string[] $tags1
* @param string[] $tags2
*/
public static function compare(array $tags1, array $tags2): bool
{
if (count($tags1) !== count($tags2)) {
@ -225,6 +234,11 @@ class Tag
return $tags1 == $tags2;
}
/**
* @param string[] $source
* @param string[] $remove
* @return string[]
*/
public static function get_diff_tags(array $source, array $remove): array
{
$before = array_map('strtolower', $source);
@ -238,6 +252,10 @@ class Tag
return $after;
}
/**
* @param string[] $tags
* @return string[]
*/
public static function sanitize_array(array $tags): array
{
global $page;

View file

@ -46,13 +46,19 @@ function SHM_FORM(string $target, string $method = "POST", bool $multipart = fal
);
}
function SHM_SIMPLE_FORM($target, ...$children): HTMLElement
/**
* @param array<string|HTMLElement|null> $children
*/
function SHM_SIMPLE_FORM(string $target, ...$children): HTMLElement
{
$form = SHM_FORM($target);
$form->appendChild(emptyHTML(...$children));
return $form;
}
/**
* @param array<string, mixed> $args
*/
function SHM_SUBMIT(string $text, array $args = []): HTMLElement
{
$args["type"] = "submit";
@ -60,6 +66,9 @@ function SHM_SUBMIT(string $text, array $args = []): HTMLElement
return INPUT($args);
}
/**
* @param array<string, mixed> $args
*/
function SHM_A(string $href, string|HTMLElement $text, string $id = "", string $class = "", array $args = []): HTMLElement
{
$args["href"] = make_link($href);
@ -83,7 +92,7 @@ function SHM_COMMAND_EXAMPLE(string $ex, string $desc): HTMLElement
);
}
function SHM_USER_FORM(User $duser, string $target, string $title, $body, $foot): HTMLElement
function SHM_USER_FORM(User $duser, string $target, string $title, HTMLElement $body, HTMLElement|string $foot): HTMLElement
{
if (is_string($foot)) {
$foot = TFOOT(TR(TD(["colspan" => "2"], INPUT(["type" => "submit", "value" => $foot]))));
@ -106,12 +115,12 @@ function SHM_USER_FORM(User $duser, string $target, string $title, $body, $foot)
* Generates a <select> element and sets up the given options.
*
* @param string $name The name attribute of <select>.
* @param array $options An array of pairs of parameters for <option> tags. First one is value, second one is text. Example: ('optionA', 'Choose Option A').
* @param array $selected_options The values of options that should be pre-selected.
* @param array<string|int, string> $options An array of pairs of parameters for <option> tags. First one is value, second one is text. Example: ('optionA', 'Choose Option A').
* @param array<string> $selected_options The values of options that should be pre-selected.
* @param bool $required Wether the <select> element is required.
* @param bool $multiple Wether the <select> element is multiple-choice.
* @param bool $empty_option Whether the first option should be an empty one.
* @param array $attrs Additional attributes dict for <select>. Example: ["id"=>"some_id", "class"=>"some_class"].
* @param array<string, mixed> $attrs Additional attributes dict for <select>. Example: ["id"=>"some_id", "class"=>"some_class"].
*/
function SHM_SELECT(string $name, array $options, array $selected_options = [], bool $required = false, bool $multiple = false, bool $empty_option = false, array $attrs = []): HTMLElement
{

View file

@ -10,6 +10,9 @@ namespace Shimmie2;
/**
* Return the unique elements of an array, case insensitively
*
* @param array<string> $array
* @return list<string>
*/
function array_iunique(array $array): array
{
@ -98,6 +101,8 @@ function full_copy(string $source, string $target): void
/**
* Return a list of all the regular files in a directory and subdirectories
*
* @return string[]
*/
function list_files(string $base, string $_sub_dir = ""): array
{
@ -203,6 +208,8 @@ if (!function_exists('http_parse_headers')) {
/**
* HTTP Headers can sometimes be lowercase which will cause issues.
* In cases like these, we need to make sure to check for them if the camelcase version does not exist.
*
* @param array<string, mixed> $headers
*/
function find_header(array $headers, string $name): ?string
{
@ -225,20 +232,22 @@ function find_header(array $headers, string $name): ?string
if (!function_exists('mb_strlen')) {
// TODO: we should warn the admin that they are missing multibyte support
/** @noinspection PhpUnusedParameterInspection */
function mb_strlen($str, $encoding): int
function mb_strlen(string $str, string $encoding): int
{
return strlen($str);
}
function mb_internal_encoding($encoding): void
function mb_internal_encoding(string $encoding): void
{
}
function mb_strtolower($str): string
function mb_strtolower(string $str): string
{
return strtolower($str);
}
}
/** @noinspection PhpUnhandledExceptionInspection */
/**
* @return class-string[]
*/
function get_subclasses_of(string $parent): array
{
$result = [];
@ -307,6 +316,8 @@ function get_base_href(): string
/**
* The opposite of the standard library's parse_url
*
* @param array<string, string|int> $parsed_url
*/
function unparse_url(array $parsed_url): string
{
@ -376,7 +387,7 @@ function url_escape(?string $input): string
/**
* Turn all manner of HTML / INI / JS / DB booleans into a PHP one
*/
function bool_escape($input): bool
function bool_escape(mixed $input): bool
{
/*
Sometimes, I don't like PHP -- this, is one of those times...
@ -634,6 +645,10 @@ function isValidDate(string $date): bool
return false;
}
/**
* @param array<string, string> $inputs
* @return array<string, mixed>
*/
function validate_input(array $inputs): array
{
$outputs = [];
@ -754,6 +769,12 @@ function join_path(string ...$paths): string
/**
* Perform callback on each item returned by an iterator.
*
* @template T
* @template U
* @param callable(U):T $callback
* @param \iterator<U> $iter
* @return \Generator<T>
*/
function iterator_map(callable $callback, \iterator $iter): \Generator
{
@ -764,6 +785,12 @@ function iterator_map(callable $callback, \iterator $iter): \Generator
/**
* Perform callback on each item returned by an iterator and combine the result into an array.
*
* @template T
* @template U
* @param callable(U):T $callback
* @param \iterator<U> $iter
* @return array<T>
*/
function iterator_map_to_array(callable $callback, \iterator $iter): array
{

View file

@ -75,11 +75,16 @@ function _namespaced_class_name(string $class): string
return str_replace("Shimmie2\\", "", $class);
}
/**
* Dump the event listeners to a file for faster loading.
*
* @param array<string, array<int, Extension>> $event_listeners
*/
function _dump_event_listeners(array $event_listeners, string $path): void
{
$p = "<"."?php\nnamespace Shimmie2;\n";
foreach (get_subclasses_of("Shimmie2\Extension") as $class) {
foreach (get_subclasses_of(Extension::class) as $class) {
$scn = _namespaced_class_name($class);
$p .= "\$$scn = new $scn(); ";
}

View file

@ -69,7 +69,11 @@ if(class_exists("\\PHPUnit\\Framework\\TestCase")) {
$_tracer->flush("data/test-trace.json");
}
private static function check_args(?array $args): array
/**
* @param array<string, mixed> $args
* @return array<string, string|mixed[]>
*/
private static function check_args(array $args): array
{
if (!$args) {
return [];
@ -84,11 +88,15 @@ if(class_exists("\\PHPUnit\\Framework\\TestCase")) {
return $args;
}
/**
* @param array<string, mixed> $get_args
* @param array<string, mixed> $post_args
*/
protected static function request(
string $method,
string $page_name,
?array $get_args = null,
?array $post_args = null
array $get_args = [],
array $post_args = []
): Page {
// use a fresh page
global $page;
@ -109,14 +117,20 @@ if(class_exists("\\PHPUnit\\Framework\\TestCase")) {
return $page;
}
protected static function get_page(string $page_name, array $args = null): Page
/**
* @param array<string, mixed> $args
*/
protected static function get_page(string $page_name, array $args = []): Page
{
return self::request("GET", $page_name, $args, null);
return self::request("GET", $page_name, $args, []);
}
protected static function post_page(string $page_name, array $args = null): Page
/**
* @param array<string, mixed> $args
*/
protected static function post_page(string $page_name, array $args = []): Page
{
return self::request("POST", $page_name, null, $args);
return self::request("POST", $page_name, [], $args);
}
// page things

View file

@ -25,7 +25,9 @@ class SearchTest extends ShimmiePHPUnitTestCase
$this->assert_search_results(["exclamation%"], [$image_id_2]);
}
// base case
/**
* @return int[]
*/
public function testUpload(): array
{
$this->log_in_as_user();
@ -41,8 +43,13 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
/********************************************************
/** ******************************************************
* Test turning a string into an abstract query
*
* @param string $tags
* @param TagCondition[] $expected_tag_conditions
* @param ImgCondition[] $expected_img_conditions
* @param string $expected_order
*/
private function assert_TTC(
string $tags,
@ -142,8 +149,16 @@ class SearchTest extends ShimmiePHPUnitTestCase
);
}
/********************************************************
/** ******************************************************
* Test turning an abstract query into SQL + fetching the results
*
* @param string[] $tcs
* @param string[] $ics
* @param string $order
* @param int $limit
* @param int $start
* @param int[] $res
* @param string[] $path
*/
private function assert_BSQ(
array $tcs = [],
@ -196,7 +211,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
* No-tag search *
* * * * * * * * * * */
#[Depends('testUpload')]
public function testBSQ_NoTags(array $image_ids): void
public function testBSQ_NoTags(): void
{
$image_ids = $this->testUpload();
$this->assert_BSQ(
@ -210,7 +225,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
* Fast-path search *
* * * * * * * * * * */
#[Depends('testUpload')]
public function testBSQ_FastPath_NoResults(array $image_ids): void
public function testBSQ_FastPath_NoResults(): void
{
$this->testUpload();
$this->assert_BSQ(
@ -221,7 +236,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_FastPath_OneResult(array $image_ids): void
public function testBSQ_FastPath_OneResult(): void
{
$image_ids = $this->testUpload();
$this->assert_BSQ(
@ -232,7 +247,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_FastPath_ManyResults(array $image_ids): void
public function testBSQ_FastPath_ManyResults(): void
{
$image_ids = $this->testUpload();
$this->assert_BSQ(
@ -243,7 +258,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_FastPath_WildNoResults(array $image_ids): void
public function testBSQ_FastPath_WildNoResults(): void
{
$this->testUpload();
$this->assert_BSQ(
@ -262,7 +277,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
* https://github.com/shish/shimmie2/issues/547
*/
#[Depends('testUpload')]
public function testBSQ_FastPath_WildOneResult(array $image_ids): void
public function testBSQ_FastPath_WildOneResult(): void
{
$image_ids = $this->testUpload();
$this->assert_BSQ(
@ -277,7 +292,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
* when a wildcard matches one image multiple times.
*/
#[Depends('testUpload')]
public function testBSQ_FastPath_WildManyResults(array $image_ids): void
public function testBSQ_FastPath_WildManyResults(): void
{
$image_ids = $this->testUpload();
// two images match comp* - one matches it once, one matches it twice
@ -292,7 +307,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
* General search *
* * * * * * * * * * */
#[Depends('testUpload')]
public function testBSQ_GeneralPath_NoResults(array $image_ids): void
public function testBSQ_GeneralPath_NoResults(): void
{
$this->testUpload();
# multiple tags, one of which doesn't exist
@ -305,7 +320,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_GeneralPath_OneResult(array $image_ids): void
public function testBSQ_GeneralPath_OneResult(): void
{
$image_ids = $this->testUpload();
$this->assert_BSQ(
@ -324,7 +339,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
* https://github.com/shish/shimmie2/issues/547
*/
#[Depends('testUpload')]
public function testBSQ_GeneralPath_WildOneResult(array $image_ids): void
public function testBSQ_GeneralPath_WildOneResult(): void
{
$image_ids = $this->testUpload();
$this->assert_BSQ(
@ -335,7 +350,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_GeneralPath_ManyResults(array $image_ids): void
public function testBSQ_GeneralPath_ManyResults(): void
{
$image_ids = $this->testUpload();
$this->assert_BSQ(
@ -346,7 +361,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_GeneralPath_WildManyResults(array $image_ids): void
public function testBSQ_GeneralPath_WildManyResults(): void
{
$image_ids = $this->testUpload();
$this->assert_BSQ(
@ -357,7 +372,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_GeneralPath_SubtractValidFromResults(array $image_ids): void
public function testBSQ_GeneralPath_SubtractValidFromResults(): void
{
$image_ids = $this->testUpload();
$this->assert_BSQ(
@ -368,7 +383,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_GeneralPath_SubtractNotValidFromResults(array $image_ids): void
public function testBSQ_GeneralPath_SubtractNotValidFromResults(): void
{
$image_ids = $this->testUpload();
$this->assert_BSQ(
@ -379,7 +394,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_GeneralPath_SubtractValidFromDefault(array $image_ids): void
public function testBSQ_GeneralPath_SubtractValidFromDefault(): void
{
$image_ids = $this->testUpload();
// negative tag alone, should remove the image with that tag
@ -391,7 +406,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_GeneralPath_SubtractNotValidFromDefault(array $image_ids): void
public function testBSQ_GeneralPath_SubtractNotValidFromDefault(): void
{
$image_ids = $this->testUpload();
// negative that doesn't exist, should return all results
@ -403,7 +418,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_GeneralPath_SubtractMultipleNotValidFromDefault(array $image_ids): void
public function testBSQ_GeneralPath_SubtractMultipleNotValidFromDefault(): void
{
$image_ids = $this->testUpload();
// multiple negative tags that don't exist, should return all results
@ -418,7 +433,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
* Meta Search *
* * * * * * * * * * */
#[Depends('testUpload')]
public function testBSQ_ImgCond_NoResults(array $image_ids): void
public function testBSQ_ImgCond_NoResults(): void
{
$this->testUpload();
$this->assert_BSQ(
@ -434,7 +449,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_ImgCond_OneResult(array $image_ids): void
public function testBSQ_ImgCond_OneResult(): void
{
$image_ids = $this->testUpload();
$this->assert_BSQ(
@ -455,7 +470,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
}
#[Depends('testUpload')]
public function testBSQ_ImgCond_ManyResults(array $image_ids): void
public function testBSQ_ImgCond_ManyResults(): void
{
$image_ids = $this->testUpload();
@ -480,7 +495,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
* Mixed *
* * * * * * * * * * */
#[Depends('testUpload')]
public function testBSQ_TagCondWithImgCond(array $image_ids): void
public function testBSQ_TagCondWithImgCond(): void
{
$image_ids = $this->testUpload();
// multiple tags, many results

View file

@ -44,6 +44,7 @@ class User
* One will very rarely construct a user directly, more common
* would be to use User::by_id, User::by_session, etc.
*
* @param array<string|int, mixed> $row
* @throws SCoreException
*/
public function __construct(array $row)

View file

@ -23,8 +23,13 @@ class UserClass
#[Field]
public ?string $name = null;
public ?UserClass $parent = null;
/** @var array<string, bool> */
public array $abilities = [];
/**
* @param array<string, bool> $abilities
*/
public function __construct(string $name, string $parent = null, array $abilities = [])
{
global $_shm_user_classes;
@ -39,6 +44,9 @@ class UserClass
$_shm_user_classes[$name] = $this;
}
/**
* @return string[]
*/
#[Field(type: "[Permission!]!")]
public function permissions(): array
{

View file

@ -285,12 +285,16 @@ function load_balance_url(string $tmpl, string $hash, int $n = 0): string
return $tmpl;
}
/**
* @return null|array<string, mixed>
*/
function fetch_url(string $url, string $mfile): ?array
{
global $config;
if ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "curl" && function_exists("curl_init")) {
$ch = curl_init($url);
assert($ch !== false);
$fp = fopen($mfile, "w");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
@ -397,6 +401,9 @@ function path_to_tags(string $path): array
return $tags;
}
/**
* @return string[]
*/
function get_dir_contents(string $dir): array
{
assert(!empty($dir));
@ -442,7 +449,9 @@ function remove_empty_dirs(string $dir): bool
return $result;
}
/**
* @return string[]
*/
function get_files_recursively(string $dir): array
{
assert(!empty($dir));
@ -475,6 +484,8 @@ function get_files_recursively(string $dir): array
/**
* Returns amount of files & total size of dir.
*
* @return array{"path": string, "total_files": int, "total_mb": string}
*/
function scan_dir(string $path): array
{

View file

@ -174,6 +174,7 @@ class AliasEditor extends Extension
$csv = "";
$aliases = $database->get_pairs("SELECT oldtag, newtag FROM aliases ORDER BY newtag");
foreach ($aliases as $old => $new) {
assert(is_string($new));
$csv .= "\"$old\",\"$new\"\n";
}
return $csv;

View file

@ -174,7 +174,9 @@ class Approval extends Extension
}
}
/**
* @param string[] $context
*/
private function no_approval_query(array $context): bool
{
foreach ($context as $term) {
@ -185,7 +187,7 @@ class Approval extends Extension
return true;
}
public static function approve_image($image_id)
public static function approve_image(int $image_id): void
{
global $database, $user;
@ -195,7 +197,7 @@ class Approval extends Extension
);
}
public static function disapprove_image($image_id)
public static function disapprove_image(int $image_id): void
{
global $database;

View file

@ -495,43 +495,52 @@ class Artists extends Extension
return (int)$database->get_one("SELECT artist_id FROM artist_urls WHERE id = :id", ['id' => $urlID]);
}
private function delete_alias(int $aliasID)
private function delete_alias(int $aliasID): void
{
global $database;
$database->execute("DELETE FROM artist_alias WHERE id = :id", ['id' => $aliasID]);
}
private function delete_url(int $urlID)
private function delete_url(int $urlID): void
{
global $database;
$database->execute("DELETE FROM artist_urls WHERE id = :id", ['id' => $urlID]);
}
private function delete_member(int $memberID)
private function delete_member(int $memberID): void
{
global $database;
$database->execute("DELETE FROM artist_members WHERE id = :id", ['id' => $memberID]);
}
/**
* @return array<string, mixed>
*/
private function get_alias_by_id(int $aliasID): array
{
global $database;
return $database->get_row("SELECT * FROM artist_alias WHERE id = :id", ['id' => $aliasID]);
}
/**
* @return array<string, mixed>
*/
private function get_url_by_id(int $urlID): array
{
global $database;
return $database->get_row("SELECT * FROM artist_urls WHERE id = :id", ['id' => $urlID]);
}
/**
* @return array<string, mixed>
*/
private function get_member_by_id(int $memberID): array
{
global $database;
return $database->get_row("SELECT * FROM artist_members WHERE id = :id", ['id' => $memberID]);
}
private function update_artist()
private function update_artist(): void
{
global $user;
$inputs = validate_input([
@ -629,7 +638,7 @@ class Artists extends Extension
}
}
private function update_alias()
private function update_alias(): void
{
global $user;
$inputs = validate_input([
@ -639,7 +648,7 @@ class Artists extends Extension
$this->save_existing_alias($inputs['aliasID'], $inputs['alias'], $user->id);
}
private function save_existing_alias(int $aliasID, string $alias, int $userID)
private function save_existing_alias(int $aliasID, string $alias, int $userID): void
{
global $database;
$database->execute(
@ -648,7 +657,7 @@ class Artists extends Extension
);
}
private function update_url()
private function update_url(): void
{
global $user;
$inputs = validate_input([
@ -658,7 +667,7 @@ class Artists extends Extension
$this->save_existing_url($inputs['urlID'], $inputs['url'], $user->id);
}
private function save_existing_url(int $urlID, string $url, int $userID)
private function save_existing_url(int $urlID, string $url, int $userID): void
{
global $database;
$database->execute(
@ -667,7 +676,7 @@ class Artists extends Extension
);
}
private function update_member()
private function update_member(): void
{
global $user;
$inputs = validate_input([
@ -677,7 +686,7 @@ class Artists extends Extension
$this->save_existing_member($inputs['memberID'], $inputs['name'], $user->id);
}
private function save_existing_member(int $memberID, string $memberName, int $userID)
private function save_existing_member(int $memberID, string $memberName, int $userID): void
{
global $database;
$database->execute(
@ -772,6 +781,9 @@ class Artists extends Extension
return ($result != 0);
}
/**
* @return array<string, mixed>
*/
private function get_artist(int $artistID): array
{
global $database;
@ -786,6 +798,9 @@ class Artists extends Extension
return $result;
}
/**
* @return array<string, mixed>
*/
private function get_members(int $artistID): array
{
global $database;
@ -802,6 +817,9 @@ class Artists extends Extension
return $result;
}
/**
* @return array<string, mixed>
*/
private function get_urls(int $artistID): array
{
global $database;
@ -837,7 +855,7 @@ class Artists extends Extension
);
}
private function delete_artist(int $artistID)
private function delete_artist(int $artistID): void
{
global $database;
$database->execute(
@ -849,7 +867,7 @@ class Artists extends Extension
/*
* HERE WE GET THE LIST OF ALL ARTIST WITH PAGINATION
*/
private function get_listing(PageRequestEvent $event)
private function get_listing(PageRequestEvent $event): void
{
global $config, $database;
@ -927,7 +945,7 @@ class Artists extends Extension
ON a.id = aa.artist_id
");
$totalPages = ceil($count / $artistsPerPage);
$totalPages = (int)ceil($count / $artistsPerPage);
$this->theme->list_artists($listing, $pageNumber + 1, $totalPages);
}
@ -935,7 +953,7 @@ class Artists extends Extension
/*
* HERE WE ADD AN ALIAS
*/
private function add_urls()
private function add_urls(): void
{
global $user;
$inputs = validate_input([
@ -952,7 +970,7 @@ class Artists extends Extension
}
}
private function save_new_url(int $artistID, string $url, int $userID)
private function save_new_url(int $artistID, string $url, int $userID): void
{
global $database;
@ -962,7 +980,7 @@ class Artists extends Extension
);
}
private function add_alias()
private function add_alias(): void
{
global $user;
$inputs = validate_input([
@ -979,7 +997,7 @@ class Artists extends Extension
}
}
private function save_new_alias(int $artistID, string $alias, int $userID)
private function save_new_alias(int $artistID, string $alias, int $userID): void
{
global $database;
@ -989,7 +1007,7 @@ class Artists extends Extension
);
}
private function add_members()
private function add_members(): void
{
global $user;
$inputs = validate_input([
@ -1006,7 +1024,7 @@ class Artists extends Extension
}
}
private function save_new_member(int $artistID, string $member, int $userID)
private function save_new_member(int $artistID, string $member, int $userID): void
{
global $database;
@ -1040,6 +1058,8 @@ class Artists extends Extension
/**
* HERE WE GET THE INFO OF THE ALIAS
*
* @return array<string, mixed>
*/
private function get_alias(int $artistID): array
{

View file

@ -9,6 +9,12 @@ use MicroHTML\HTMLElement;
use function MicroHTML\emptyHTML;
use function MicroHTML\{INPUT,P};
/**
* @phpstan-type ArtistArtist array{id:int,artist_id:int,user_name:string,name:string,notes:string,type:string,posts:int}
* @phpstan-type ArtistAlias array{id:int,alias_id:int,alias_name:string,alias:string}
* @phpstan-type ArtistMember array{id:int,name:string}
* @phpstan-type ArtistUrl array{id:int,url:string}
*/
class ArtistsTheme extends Themelet
{
public function get_author_editor_html(string $author): HTMLElement
@ -20,7 +26,7 @@ class ArtistsTheme extends Themelet
);
}
public function sidebar_options(string $mode, ?int $artistID = null, $is_admin = false): void
public function sidebar_options(string $mode, ?int $artistID = null, bool $is_admin = false): void
{
global $page, $user;
@ -77,7 +83,13 @@ class ArtistsTheme extends Themelet
}
}
public function show_artist_editor($artist, $aliases, $members, $urls)
/**
* @param ArtistArtist $artist
* @param ArtistAlias[] $aliases
* @param ArtistMember[] $members
* @param ArtistUrl[] $urls
*/
public function show_artist_editor(array $artist, array $aliases, array $members, array $urls): void
{
global $user;
@ -137,7 +149,7 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Edit artist", $html, "main", 10));
}
public function new_artist_composer()
public function new_artist_composer(): void
{
global $page, $user;
@ -158,7 +170,10 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Artists", $html, "main", 10));
}
public function list_artists($artists, $pageNumber, $totalPages)
/**
* @param ArtistArtist[] $artists
*/
public function list_artists(array $artists, int $pageNumber, int $totalPages): void
{
global $user, $page;
@ -237,7 +252,7 @@ class ArtistsTheme extends Themelet
$this->display_paginator($page, "artist/list", null, $pageNumber, $totalPages);
}
public function show_new_alias_composer($artistID)
public function show_new_alias_composer(int $artistID): void
{
global $user;
@ -256,7 +271,7 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Artist Aliases", $html, "main", 20));
}
public function show_new_member_composer($artistID)
public function show_new_member_composer(int $artistID): void
{
global $user;
@ -275,7 +290,7 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Artist members", $html, "main", 30));
}
public function show_new_url_composer($artistID)
public function show_new_url_composer(int $artistID): void
{
global $user;
@ -294,7 +309,10 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Artist URLs", $html, "main", 40));
}
public function show_alias_editor($alias)
/**
* @param ArtistAlias $alias
*/
public function show_alias_editor(array $alias): void
{
global $user;
@ -312,7 +330,10 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Edit Alias", $html, "main", 10));
}
public function show_url_editor($url)
/**
* @param ArtistUrl $url
*/
public function show_url_editor(array $url): void
{
global $user;
@ -330,7 +351,10 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Edit URL", $html, "main", 10));
}
public function show_member_editor($member)
/**
* @param ArtistMember $member
*/
public function show_member_editor(array $member): void
{
global $user;
@ -348,7 +372,14 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Edit Member", $html, "main", 10));
}
public function show_artist($artist, $aliases, $members, $urls, $images, $userIsLogged, $userIsAdmin)
/**
* @param ArtistArtist $artist
* @param ArtistAlias[] $aliases
* @param ArtistMember[] $members
* @param ArtistUrl[] $urls
* @param Image[] $images
*/
public function show_artist(array $artist, array $aliases, array $members, array $urls, array $images, bool $userIsLogged, bool $userIsAdmin): void
{
global $page;
@ -416,6 +447,9 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Artist Posts", $artist_images, "main", 20));
}
/**
* @param ArtistAlias[] $aliases
*/
private function render_aliases(array $aliases, bool $userIsLogged, bool $userIsAdmin): string
{
$html = "";
@ -462,6 +496,9 @@ class ArtistsTheme extends Themelet
return $html;
}
/**
* @param ArtistMember[] $members
*/
private function render_members(array $members, bool $userIsLogged, bool $userIsAdmin): string
{
$html = "";
@ -506,6 +543,9 @@ class ArtistsTheme extends Themelet
return $html;
}
/**
* @param ArtistUrl[] $urls
*/
private function render_urls(array $urls, bool $userIsLogged, bool $userIsAdmin): string
{
$html = "";

View file

@ -186,6 +186,7 @@ class AutoTagger extends Extension
$csv = "";
$pairs = $database->get_pairs("SELECT tag, additional_tags FROM auto_tag ORDER BY tag");
foreach ($pairs as $old => $new) {
assert(is_string($new));
$csv .= "\"$old\",\"$new\"\n";
}
return $csv;
@ -209,7 +210,7 @@ class AutoTagger extends Extension
return $i;
}
private function add_auto_tag(string $tag, string $additional_tags)
private function add_auto_tag(string $tag, string $additional_tags): void
{
global $database;
$existing_tags = $database->get_one("SELECT additional_tags FROM auto_tag WHERE LOWER(tag)=LOWER(:tag)", ["tag" => $tag]);
@ -250,7 +251,7 @@ class AutoTagger extends Extension
$this->apply_new_auto_tag($tag);
}
private function apply_new_auto_tag(string $tag)
private function apply_new_auto_tag(string $tag): void
{
global $database;
$tag_id = $database->get_one("SELECT id FROM tags WHERE LOWER(tag) = LOWER(:tag)", ["tag" => $tag]);
@ -264,7 +265,7 @@ class AutoTagger extends Extension
}
}
private function remove_auto_tag(string $tag)
private function remove_auto_tag(string $tag): void
{
global $database;
@ -273,6 +274,7 @@ class AutoTagger extends Extension
/**
* @param string[] $tags_mixed
* @return string[]
*/
private function apply_auto_tags(array $tags_mixed): array
{

View file

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Shimmie2;
use MicroHTML\HTMLElement;
class AutoTaggerTheme extends Themelet
{
/**
@ -11,7 +13,7 @@ class AutoTaggerTheme extends Themelet
*
* Note: $can_manage = whether things like "add new alias" should be shown
*/
public function display_auto_tagtable($table, $paginator): void
public function display_auto_tagtable(HTMLElement $table, HTMLElement $paginator): void
{
global $page, $user;

View file

@ -27,6 +27,9 @@ class AutoComplete extends Extension
}
}
/**
* @return array<string, int>
*/
private function complete(string $search, int $limit): array
{
global $cache, $database;

View file

@ -97,6 +97,9 @@ xanax
}
}
/**
* @return string[]
*/
private function get_words(): array
{
global $config;

View file

@ -6,7 +6,7 @@ namespace Shimmie2;
class BanWordsTest extends ShimmiePHPUnitTestCase
{
public function check_blocked($image_id, $words)
public function check_blocked(int $image_id, string $words): void
{
global $user;
try {

View file

@ -101,13 +101,13 @@ class BBCodeTest extends ShimmiePHPUnitTestCase
);
}
private function filter($in): string
private function filter(string $in): string
{
$bb = new BBCode();
return $bb->_format($in);
}
private function strip($in): string
private function strip(string $in): string
{
$bb = new BBCode();
return $bb->strip($in);

View file

@ -16,7 +16,10 @@ use function MicroHTML\OPTION;
class BlocksTheme extends Themelet
{
public function display_blocks($blocks): void
/**
* @param array<array{id:int,title:string,area:string,priority:int,userclass:string,pages:string,content:string}> $blocks
*/
public function display_blocks(array $blocks): void
{
global $page;

View file

@ -136,7 +136,7 @@ class Blotter extends Extension
$this->display_blotter();
}
private function display_blotter()
private function display_blotter(): void
{
global $database, $config;
$limit = $config->get_int("blotter_recent", 5);

View file

@ -4,9 +4,15 @@ declare(strict_types=1);
namespace Shimmie2;
/**
* @phpstan-type BlotterEntry array{id:int,entry_date:string,entry_text:string,important:bool}
*/
class BlotterTheme extends Themelet
{
public function display_editor($entries): void
/**
* @param BlotterEntry[] $entries
*/
public function display_editor(array $entries): void
{
global $page;
$html = $this->get_html_for_blotter_editor($entries);
@ -16,7 +22,10 @@ class BlotterTheme extends Themelet
$page->add_block(new Block("Navigation", "<a href='".make_link()."'>Index</a>", "left", 0));
}
public function display_blotter_page($entries): void
/**
* @param BlotterEntry[] $entries
*/
public function display_blotter_page(array $entries): void
{
global $page;
$html = $this->get_html_for_blotter_page($entries);
@ -25,6 +34,9 @@ class BlotterTheme extends Themelet
$page->add_block(new Block("Blotter Entries", $html, "main", 10));
}
/**
* @param BlotterEntry[] $entries
*/
public function display_blotter(array $entries): void
{
global $page, $config;
@ -33,6 +45,9 @@ class BlotterTheme extends Themelet
$page->add_block(new Block(null, $html, $position, 20));
}
/**
* @param BlotterEntry[] $entries
*/
private function get_html_for_blotter_editor(array $entries): string
{
global $user;
@ -104,6 +119,9 @@ class BlotterTheme extends Themelet
return $html;
}
/**
* @param BlotterEntry[] $entries
*/
private function get_html_for_blotter_page(array $entries): string
{
/**
@ -135,25 +153,27 @@ class BlotterTheme extends Themelet
return $html;
}
/**
* @param BlotterEntry[] $entries
*/
private function get_html_for_blotter(array $entries): string
{
global $config;
$i_color = $config->get_string("blotter_color", "#FF0000");
$position = $config->get_string("blotter_position", "subheading");
$entries_list = "";
$num_entries = count($entries);
for ($i = 0 ; $i < $num_entries ; $i++) {
foreach($entries as $entry) {
/**
* Blotter entries
*/
// Reset variables:
$i_open = "";
$i_close = "";
//$id = $entries[$i]['id'];
$messy_date = $entries[$i]['entry_date'];
//$id = $entry['id'];
$messy_date = $entry['entry_date'];
$clean_date = date("m/d/y", strtotime($messy_date));
$entry_text = $entries[$i]['entry_text'];
if ($entries[$i]['important'] == 'Y') {
$entry_text = $entry['entry_text'];
if ($entry['important'] == 'Y') {
$i_open = "<span style='color: #$i_color'>";
$i_close = "</span>";
}

View file

@ -13,10 +13,14 @@ class BulkActionException extends SCoreException
}
class BulkActionBlockBuildingEvent extends Event
{
/**
* @var array<array{block:string,access_key:?string,confirmation_message:string,action:string,button_text:string,position:int}>
*/
public array $actions = [];
/** @var string[] */
public array $search_terms = [];
public function add_action(string $action, string $button_text, string $access_key = null, string $confirmation_message = "", string $block = "", int $position = 40)
public function add_action(string $action, string $button_text, string $access_key = null, string $confirmation_message = "", string $block = "", int $position = 40): void
{
if (!empty($access_key)) {
assert(strlen($access_key) == 1);
@ -28,13 +32,13 @@ class BulkActionBlockBuildingEvent extends Event
}
$this->actions[] = [
"block" => $block,
"access_key" => $access_key,
"confirmation_message" => $confirmation_message,
"action" => $action,
"button_text" => $button_text,
"position" => $position
];
"block" => $block,
"access_key" => $access_key,
"confirmation_message" => $confirmation_message,
"action" => $action,
"button_text" => $button_text,
"position" => $position
];
}
}
@ -194,29 +198,42 @@ class BulkActions extends Extension
}
}
/**
* @param int[] $data
* @return \Generator<Image>
*/
private function yield_items(array $data): \Generator
{
foreach ($data as $id) {
if (is_numeric($id)) {
$image = Image::by_id($id);
if ($image != null) {
yield $image;
}
$image = Image::by_id($id);
if ($image != null) {
yield $image;
}
}
}
/**
* @return \Generator<Image>
*/
private function yield_search_results(string $query): \Generator
{
$tags = Tag::explode($query);
return Search::find_images_iterable(0, null, $tags);
}
private function sort_blocks($a, $b)
/**
* @param array{position: int} $a
* @param array{position: int} $b
*/
private function sort_blocks(array $a, array $b): int
{
return $a["position"] - $b["position"];
}
/**
* @param iterable<Image> $posts
* @return array{0: int, 1: int}
*/
private function delete_posts(iterable $posts): array
{
global $page;
@ -240,6 +257,9 @@ class BulkActions extends Extension
return [$total, $size];
}
/**
* @param iterable<Image> $items
*/
private function tag_items(iterable $items, string $tags, bool $replace): int
{
$tags = Tag::explode($tags);
@ -280,6 +300,9 @@ class BulkActions extends Extension
return $total;
}
/**
* @param iterable<Image> $items
*/
private function set_source(iterable $items, string $source): int
{
global $page;

View file

@ -6,6 +6,9 @@ namespace Shimmie2;
class BulkActionsTheme extends Themelet
{
/**
* @param array<array{block:string,access_key:?string,confirmation_message:string,action:string,button_text:string,position:int}> $actions
*/
public function display_selector(Page $page, array $actions, string $query): void
{
$body = "<input type='hidden' name='bulk_selected_ids' id='bulk_selected_ids' />

View file

@ -50,8 +50,10 @@ class BulkAddCSV extends Extension
/**
* Generate the necessary DataUploadEvent for a given image and tags.
*
* @param string[] $tags
*/
private function add_image(string $tmpname, string $filename, array $tags, string $source, string $rating, string $thumbfile)
private function add_image(string $tmpname, string $filename, array $tags, string $source, string $rating, string $thumbfile): void
{
global $database;
$database->with_savepoint(function () use ($tmpname, $filename, $tags, $source, $rating, $thumbfile) {
@ -72,7 +74,7 @@ class BulkAddCSV extends Extension
});
}
private function add_csv(string $csvfile)
private function add_csv(string $csvfile): void
{
if (!file_exists($csvfile)) {
$this->theme->add_status("Error", "$csvfile not found");

View file

@ -6,6 +6,7 @@ namespace Shimmie2;
class BulkAddCSVTheme extends Themelet
{
/** @var Block[] */
private array $messages = [];
/*
@ -44,7 +45,7 @@ class BulkAddCSVTheme extends Themelet
$page->add_block(new Block("Bulk Add CSV", $html));
}
public function add_status($title, $body)
public function add_status(string $title, string $body): void
{
$this->messages[] = new Block($title, $body);
}

View file

@ -7,6 +7,7 @@ namespace Shimmie2;
class BulkExportEvent extends Event
{
public Image $image;
/** @var array<string,mixed> */
public array $fields = [];
public function __construct(Image $image)
@ -20,9 +21,13 @@ class BulkExportEvent extends Event
class BulkImportEvent extends Event
{
public Image $image;
/** @var array<string,mixed> */
public array $fields = [];
public function __construct(Image $image, $fields)
/**
* @param array<string,mixed> $fields
*/
public function __construct(Image $image, array $fields)
{
parent::__construct();
$this->image = $image;

View file

@ -155,6 +155,9 @@ class BulkImportExport extends DataHandlerExtension
return false;
}
/**
* @return array<mixed>
*/
private function get_export_data(\ZipArchive $zip): ?array
{
$info = $zip->getStream(self::EXPORT_INFO_FILE_NAME);

View file

@ -63,7 +63,10 @@ class Comment
#[Field]
public string $posted;
public function __construct($row)
/**
* @param array<string,mixed> $row
*/
public function __construct(array $row)
{
$this->owner = null;
$this->owner_id = (int)$row['user_id'];
@ -96,6 +99,9 @@ class Comment
return $this->owner;
}
/**
* @return Comment[]
*/
#[Field(extends: "Post", name: "comments", type: "[Comment!]!")]
public static function get_comments(Image $post): array
{
@ -223,7 +229,7 @@ class CommentList extends Extension
$event->add_disallow("comment");
}
private function onPageRequest_add()
private function onPageRequest_add(): void
{
global $user, $page;
if (isset($_POST['image_id']) && isset($_POST['comment'])) {
@ -238,7 +244,7 @@ class CommentList extends Extension
}
}
private function onPageRequest_delete(PageRequestEvent $event)
private function onPageRequest_delete(PageRequestEvent $event): void
{
global $user, $page;
if ($user->can(Permissions::DELETE_COMMENT)) {
@ -254,7 +260,7 @@ class CommentList extends Extension
}
}
private function onPageRequest_bulk_delete()
private function onPageRequest_bulk_delete(): void
{
global $user, $database, $page;
if ($user->can(Permissions::DELETE_COMMENT) && !empty($_POST["ip"])) {
@ -279,7 +285,7 @@ class CommentList extends Extension
}
}
private function onPageRequest_list(PageRequestEvent $event)
private function onPageRequest_list(PageRequestEvent $event): void
{
global $cache, $config, $database, $user;
@ -332,7 +338,7 @@ class CommentList extends Extension
$this->theme->display_comment_list($images, $current_page + 1, $total_pages, $user->can(Permissions::CREATE_COMMENT));
}
private function onPageRequest_beta_search(PageRequestEvent $event)
private function onPageRequest_beta_search(PageRequestEvent $event): void
{
$search = $event->get_arg(1);
$page_num = $event->try_page_num(2);
@ -448,6 +454,7 @@ class CommentList extends Extension
}
/**
* @param array<string,mixed> $args
* @return Comment[]
*/
private static function get_generic_comments(string $query, array $args): array
@ -603,7 +610,7 @@ class CommentList extends Extension
}
// do some checks
private function add_comment_wrapper(int $image_id, User $user, string $comment)
private function add_comment_wrapper(int $image_id, User $user, string $comment): void
{
global $database, $page;
@ -628,7 +635,7 @@ class CommentList extends Extension
log_info("comment", "Comment #$cid added to >>$image_id: $snippet");
}
private function comment_checks(int $image_id, User $user, string $comment)
private function comment_checks(int $image_id, User $user, string $comment): void
{
global $config, $page;

View file

@ -8,10 +8,13 @@ class CommentListTheme extends Themelet
{
private bool $show_anon_id = false;
private int $anon_id = 1;
/** @var array<string,int> */
private array $anon_map = [];
/**
* Display a page with a list of images, and for each image, the image's comments.
*
* @param array<array{0: Image, 1: Comment[]}> $images
*/
public function display_comment_list(array $images, int $page_number, int $total_pages, bool $can_post): void
{
@ -164,6 +167,9 @@ class CommentListTheme extends Themelet
$page->add_block(new Block("Comments", $html, "left", 70, "comment-list-user"));
}
/**
* @param Comment[] $comments
*/
public function display_all_user_comments(array $comments, int $page_number, int $total_pages, User $user): void
{
global $page;

View file

@ -139,7 +139,7 @@ class CronUploader extends Extension
}
}
private function restage_folder(string $folder)
private function restage_folder(string $folder): void
{
global $page;
if (empty($folder)) {
@ -196,7 +196,7 @@ class CronUploader extends Extension
}
}
private function clear_folder($folder)
private function clear_folder(string $folder): void
{
global $page, $user_config;
$path = join_path($user_config->get_string(CronUploaderConfig::DIR), $folder);
@ -414,7 +414,7 @@ class CronUploader extends Extension
}
}
private function move_uploaded(string $path, string $filename, string $output_subdir, bool $corrupt = false)
private function move_uploaded(string $path, string $filename, string $output_subdir, bool $corrupt = false): void
{
global $user_config;
@ -454,6 +454,8 @@ class CronUploader extends Extension
/**
* Generate the necessary DataUploadEvent for a given image and tags.
*
* @param string[] $tags
*/
private function add_image(string $tmpname, string $filename, array $tags): DataUploadEvent
{

View file

@ -17,6 +17,12 @@ use function MicroHTML\emptyHTML;
class CronUploaderTheme extends Themelet
{
/**
* @param array{path:string,total_files:int,total_mb:string} $queue_dirinfo
* @param array{path:string,total_files:int,total_mb:string} $uploaded_dirinfo
* @param array{path:string,total_files:int,total_mb:string} $failed_dirinfo
* @param array<array{date_sent:string,message:string}>|null $log_entries
*/
public function display_documentation(
bool $running,
array $queue_dirinfo,
@ -25,7 +31,7 @@ class CronUploaderTheme extends Themelet
string $cron_cmd,
string $cron_url,
?array $log_entries
) {
): void {
global $page, $config, $user_config;
$info_html = "";
@ -159,6 +165,9 @@ class CronUploaderTheme extends Themelet
return (string)$html;
}
/**
* @param string[] $failed_dirs
*/
public function display_form(array $failed_dirs): void
{
global $page;

View file

@ -38,7 +38,7 @@ class CustomHtmlHeaders extends Extension
$this->handle_modified_page_title();
}
private function handle_custom_html_headers()
private function handle_custom_html_headers(): void
{
global $config, $page;
@ -48,7 +48,7 @@ class CustomHtmlHeaders extends Extension
}
}
private function handle_modified_page_title()
private function handle_modified_page_title(): void
{
global $config, $page;

View file

@ -6,6 +6,9 @@ namespace Shimmie2;
class EmoticonListTheme extends Themelet
{
/**
* @param string[] $list
*/
public function display_emotes(array $list): void
{
global $page;

View file

@ -53,6 +53,8 @@ class ET extends Extension
/**
* Collect the information and return it in a keyed array.
*
* @return array<string, mixed>
*/
private function get_info(): array
{
@ -135,6 +137,9 @@ class ET extends Extension
return $info;
}
/**
* @param array<string, mixed> $info
*/
private function to_yaml(array $info): string
{
$data = "";

View file

@ -13,10 +13,8 @@ class ETTheme extends Themelet
{
/*
* Create a page showing info
*
* $info = an array of ($name => $value)
*/
public function display_info_page($yaml): void
public function display_info_page(string $yaml): void
{
global $page;
@ -26,7 +24,7 @@ class ETTheme extends Themelet
$page->add_block(new Block("Information:", $this->build_data_form($yaml)));
}
protected function build_data_form($yaml): \MicroHTML\HTMLElement
protected function build_data_form(string $yaml): \MicroHTML\HTMLElement
{
return FORM(
["action" => "https://shimmie.shishnet.org/register.php", "method" => "POST"],

View file

@ -116,7 +116,10 @@ class ExtManager extends Extension
return $extensions;
}
private function set_things($settings)
/**
* @param array<string, bool> $settings
*/
private function set_things(array $settings): void
{
$core = ExtensionInfo::get_core_extensions();
$extras = [];
@ -133,7 +136,7 @@ class ExtManager extends Extension
/**
* @param string[] $extras
*/
private function write_config(array $extras)
private function write_config(array $extras): void
{
file_put_contents(
"data/config/extensions.conf.php",

View file

@ -238,7 +238,7 @@ class Favorites extends Extension
}
}
private function add_vote(int $image_id, int $user_id, bool $do_set)
private function add_vote(int $image_id, int $user_id, bool $do_set): void
{
global $database;
if ($do_set) {

View file

@ -22,6 +22,9 @@ class FavoritesTheme extends Themelet
);
}
/**
* @param string[] $username_array
*/
public function display_people(array $username_array): void
{
global $page;

View file

@ -206,6 +206,9 @@ class Forum extends Extension
return (int)ceil($result["count"] / $config->get_int("forumPostsPerPage"));
}
/**
* @return string[]
*/
private function sanity_check_new_thread(): array
{
$errors = [];
@ -226,6 +229,9 @@ class Forum extends Extension
return $errors;
}
/**
* @return string[]
*/
private function sanity_check_new_post(): array
{
$errors = [];

View file

@ -8,9 +8,16 @@ use MicroHTML\HTMLElement;
use function MicroHTML\{INPUT, LABEL, SMALL, TEXTAREA, TR, TD, TABLE, TH, TBODY, THEAD, DIV, A, BR, emptyHTML, SUP, rawHTML};
/**
* @phpstan-type Thread array{id:int,title:string,sticky:bool,user_name:string,uptodate:string,response_count:int}
* @phpstan-type Post array{id:int,user_name:string,user_class:string,date:string,message:string}
*/
class ForumTheme extends Themelet
{
public function display_thread_list(Page $page, $threads, $showAdminOptions, $pageNumber, $totalPages): void
/**
* @param Thread[] $threads
*/
public function display_thread_list(Page $page, array $threads, bool $showAdminOptions, int $pageNumber, int $totalPages): void
{
if (count($threads) == 0) {
$html = "There are no threads to show.";
@ -27,7 +34,7 @@ class ForumTheme extends Themelet
public function display_new_thread_composer(Page $page, $threadText = null, $threadTitle = null): void
public function display_new_thread_composer(Page $page, string $threadText = null, string $threadTitle = null): void
{
global $config, $user;
$max_characters = $config->get_int('forumMaxCharsPerPost');
@ -73,9 +80,7 @@ class ForumTheme extends Themelet
$page->add_block(new Block($blockTitle, $html, "main", 120));
}
public function display_new_post_composer(Page $page, $threadID): void
public function display_new_post_composer(Page $page, int $threadID): void
{
global $config;
@ -108,8 +113,10 @@ class ForumTheme extends Themelet
}
public function display_thread($posts, $showAdminOptions, $threadTitle, $threadID, $pageNumber, $totalPages): void
/**
* @param array<Post> $posts
*/
public function display_thread(array $posts, bool $showAdminOptions, string $threadTitle, int $threadID, int $pageNumber, int $totalPages): void
{
global $config, $page/*, $user*/;
@ -189,13 +196,16 @@ class ForumTheme extends Themelet
$page->add_block(new Block($threadTitle, $html, "main", 20));
}
public function add_actions_block(Page $page, $threadID)
public function add_actions_block(Page $page, int $threadID): void
{
$html = A(["href" => make_link("forum/nuke/".$threadID)], "Delete this thread and its posts.");
$page->add_block(new Block("Admin Actions", $html, "main", 140));
}
private function make_thread_list($threads, $showAdminOptions): HTMLElement
/**
* @param Thread[] $threads
*/
private function make_thread_list(array $threads, bool $showAdminOptions): HTMLElement
{
global $config;

View file

@ -21,7 +21,10 @@ class FourOhFour extends Extension
}
}
private function count_main($blocks): int
/**
* @param Block[] $blocks
*/
private function count_main(array $blocks): int
{
$n = 0;
foreach ($blocks as $block) {

View file

@ -115,6 +115,9 @@ class GraphQL extends Extension
}
}
/**
* @return array{error?:string,results?:array<array{error?:string,image_ids?:int[]}>}
*/
private static function handle_uploads(): array
{
global $user;
@ -135,7 +138,7 @@ class GraphQL extends Extension
break;
}
try {
$results[] = self::handle_upload($n, $common_tags, $common_source);
$results[] = ["image_ids" => self::handle_upload($n, $common_tags, $common_source)];
} catch(\Exception $e) {
$results[] = ["error" => $e->getMessage()];
}
@ -143,10 +146,14 @@ class GraphQL extends Extension
return ["results" => $results];
}
/**
* @return int[]
*/
private static function handle_upload(int $n, string $common_tags, string $common_source): array
{
global $database;
if (!empty($_POST["url$n"])) {
throw new \Exception("URLs not handled yet");
throw new UploadException("URLs not handled yet");
} else {
$ec = $_FILES["data$n"]["error"];
switch($ec) {
@ -155,9 +162,9 @@ class GraphQL extends Extension
$filename = $_FILES["data$n"]["name"];
break;
case UPLOAD_ERR_INI_SIZE:
return ["error" => "File larger than PHP can handle"];
throw new UploadException("File larger than PHP can handle");
default:
return ["error" => "Mystery error: $ec"];
throw new UploadException("Mystery error: $ec");
}
}
@ -166,13 +173,15 @@ class GraphQL extends Extension
if (!empty($_POST["source$n"])) {
$source = $_POST["source$n"];
}
$event = send_event(new DataUploadEvent($tmpname, [
'filename' => $filename,
'tags' => Tag::explode($tags),
'source' => $source,
]));
$event = $database->with_savepoint(function () use ($tmpname, $filename, $tags, $source) {
return send_event(new DataUploadEvent($tmpname, [
'filename' => $filename,
'tags' => Tag::explode($tags),
'source' => $source,
]));
});
return ["image_ids" => array_map(fn ($im) => $im->id, $event->images)];
return array_map(fn ($im) => $im->id, $event->images);
}
public function onCliGen(CliGenEvent $event): void

View file

@ -107,7 +107,10 @@ class MiniSVGParser
xml_parser_free($xml_parser);
}
public function startElement($parser, $name, $attrs): void
/**
* @param array<string, mixed> $attrs
*/
public function startElement(mixed $parser, string $name, array $attrs): void
{
if ($name == "SVG" && $this->xml_depth == 0) {
$this->width = int_escape($attrs["WIDTH"]);
@ -116,7 +119,7 @@ class MiniSVGParser
$this->xml_depth++;
}
public function endElement($parser, $name): void
public function endElement(mixed $parser, string $name): void
{
$this->xml_depth--;
}

View file

@ -39,6 +39,9 @@ class VideoFileHandler extends DataHandlerExtension
);
}
/**
* @return array<string, string>
*/
private function get_options(): array
{
$output = [];

View file

@ -6,9 +6,10 @@ namespace Shimmie2;
class HelpPageListBuildingEvent extends Event
{
/** @var array<string,string> */
public array $pages = [];
public function add_page(string $key, string $name)
public function add_page(string $key, string $name): void
{
$this->pages[$key] = $name;
}
@ -17,6 +18,7 @@ class HelpPageListBuildingEvent extends Event
class HelpPageBuildingEvent extends Event
{
public string $key;
/** @var array<string,array<Block>> */
public array $blocks = [];
public function __construct(string $key)
@ -25,7 +27,7 @@ class HelpPageBuildingEvent extends Event
$this->key = $key;
}
public function add_block(Block $block, int $position = 50)
public function add_block(Block $block, int $position = 50): void
{
if (!array_key_exists("$position", $this->blocks)) {
$this->blocks["$position"] = [];

View file

@ -6,6 +6,9 @@ namespace Shimmie2;
class HelpPagesTheme extends Themelet
{
/**
* @param array<string,string> $pages
*/
public function display_list_page(array $pages): void
{
global $page;

View file

@ -29,7 +29,7 @@ EOD
);
}
public function build_body(string $sitename, string $main_links, string $main_text, string $contact_link, $num_comma, string $counter_text): string
public function build_body(string $sitename, string $main_links, string $main_text, string $contact_link, string $num_comma, string $counter_text): string
{
$main_links_html = empty($main_links) ? "" : "<div class='space' id='links'>$main_links</div>";
$message_html = empty($main_text) ? "" : "<div class='space' id='message'>$main_text</div>";

View file

@ -215,7 +215,7 @@ class ImageIO extends Extension
$event->replace("\\n", "\n");
}
private function send_file(int $image_id, string $type)
private function send_file(int $image_id, string $type): void
{
global $config, $page;

View file

@ -4,25 +4,27 @@ declare(strict_types=1);
namespace Shimmie2;
use function MicroHTML\INPUT;
use MicroHTML\HTMLElement;
use function MicroHTML\{INPUT,emptyHTML};
class ImageBanTheme extends Themelet
{
/*
* Show all the bans
*/
public function display_bans(Page $page, $table, $paginator): void
public function display_bans(Page $page, HTMLElement $table, HTMLElement $paginator): void
{
$page->set_title("Post Bans");
$page->set_heading("Post Bans");
$page->add_block(new NavBlock());
$page->add_block(new Block("Edit Post Bans", $table . $paginator));
$page->add_block(new Block("Edit Post Bans", emptyHTML($table, $paginator)));
}
/*
* Display a link to delete an image
*/
public function get_buttons_html(Image $image): \MicroHTML\HTMLElement
public function get_buttons_html(Image $image): HTMLElement
{
return SHM_SIMPLE_FORM(
"image_hash_ban/add",

View file

@ -9,7 +9,7 @@ class ImageViewCounterTheme extends Themelet
/**
* @param Image[] $images
*/
public function view_popular(array $images)
public function view_popular(array $images): void
{
global $page, $config;
$pop_images = "";

View file

@ -21,6 +21,9 @@ class SearchTermParseEvent extends Event
public array $tag_conditions = [];
public ?string $order = null;
/**
* @param string[] $context
*/
public function __construct(int $id, string $term = null, array $context = [])
{
parent::__construct();
@ -41,17 +44,17 @@ class SearchTermParseEvent extends Event
$this->context = $context;
}
public function add_querylet(Querylet $q)
public function add_querylet(Querylet $q): void
{
$this->add_img_condition(new ImgCondition($q, $this->positive));
}
public function add_img_condition(ImgCondition $c)
public function add_img_condition(ImgCondition $c): void
{
$this->img_conditions[] = $c;
}
public function add_tag_condition(TagCondition $c)
public function add_tag_condition(TagCondition $c): void
{
$this->tag_conditions[] = $c;
}
@ -63,7 +66,9 @@ class SearchTermParseException extends SCoreException
class PostListBuildingEvent extends Event
{
/** @var string[] */
public array $search_terms = [];
/** @var array<int,string> */
public array $parts = [];
/**
@ -75,7 +80,7 @@ class PostListBuildingEvent extends Event
$this->search_terms = $search;
}
public function add_control(string $html, int $position = 50)
public function add_control(string $html, int $position = 50): void
{
while (isset($this->parts[$position])) {
$position++;

View file

@ -13,9 +13,13 @@ class IndexTheme extends Themelet
{
protected int $page_number;
protected int $total_pages;
/** @var string[] */
protected array $search_terms;
public function set_page(int $page_number, int $total_pages, array $search_terms)
/**
* @param string[] $search_terms
*/
public function set_page(int $page_number, int $total_pages, array $search_terms): void
{
$this->page_number = $page_number;
$this->total_pages = $total_pages;
@ -109,7 +113,7 @@ and of course start organising your images :-)
return $table;
}
protected function display_shortwiki(Page $page)
protected function display_shortwiki(Page $page): void
{
global $config;
@ -141,7 +145,7 @@ and of course start organising your images :-)
/**
* @param Image[] $images
*/
protected function display_page_header(Page $page, array $images)
protected function display_page_header(Page $page, array $images): void
{
global $config;
@ -167,7 +171,7 @@ and of course start organising your images :-)
/**
* @param Image[] $images
*/
protected function display_page_images(Page $page, array $images)
protected function display_page_images(Page $page, array $images): void
{
if (count($this->search_terms) > 0) {
if ($this->page_number > 3) {

View file

@ -130,7 +130,7 @@ class IPBan extends Extension
// Check if our current IP is in either of the ban lists
$active_ban_id = (
$this->find_active_ban($ips, get_real_ip(), $networks)
$this->find_active_ban(get_real_ip(), $ips, $networks)
);
// If an active ban is found, act on it
@ -355,11 +355,12 @@ class IPBan extends Extension
}
}
public function find_active_ban($ips, $remote, $networks)
/**
* @param array<string,int> $ips
* @param array<string,int> $networks
*/
public function find_active_ban(string $remote, array $ips, array $networks): ?int
{
if (!$remote) {
return null;
}
$active_ban_id = null;
if (isset($ips[$remote])) {
$active_ban_id = $ips[$remote];

View file

@ -4,9 +4,13 @@ declare(strict_types=1);
namespace Shimmie2;
use MicroHTML\HTMLElement;
use function MicroHTML\emptyHTML;
class IPBanTheme extends Themelet
{
public function display_bans(Page $page, $table, $paginator): void
public function display_bans(Page $page, HTMLElement $table, HTMLElement $paginator): void
{
$html = "
<a href='".make_link("ip_ban/list", "r__size=1000000")."'>Show All Active</a> /

View file

@ -27,6 +27,9 @@ class LinkImage extends Extension
$config->set_default_string("ext_link-img_text-link_format", '$title - $id ($ext $size $filesize)');
}
/**
* @return array{thumb_src: string, image_src: string, post_link: string, text_link: string}
*/
private function data(Image $image): array
{
global $config;
@ -38,6 +41,7 @@ class LinkImage extends Extension
'thumb_src' => make_http($image->get_thumb_link()),
'image_src' => make_http($image->get_image_link()),
'post_link' => make_http(make_link("post/view/{$image->id}")),
'text_link' => $text_link];
'text_link' => $text_link
];
}
}

View file

@ -6,14 +6,16 @@ namespace Shimmie2;
class LinkImageTheme extends Themelet
{
public function links_block(Page $page, $data)
/**
* @param array{thumb_src:string,image_src:string,post_link:string,text_link:string} $data
*/
public function links_block(Page $page, array $data): void
{
$thumb_src = $data['thumb_src'];
$image_src = $data['image_src'];
$post_link = $data['post_link'];
$text_link = $data['text_link'];
$page->add_block(new Block(
"Link to Post",
"
@ -93,7 +95,7 @@ class LinkImageTheme extends Themelet
return $text;
}
protected function link_code(string $label, string $content, $id = null): string
protected function link_code(string $label, string $content, string $id): string
{
return "
<tr>

View file

@ -26,6 +26,9 @@ class LinkScan extends Extension
}
}
/**
* @return int[]
*/
private function scan(string $text): array
{
$ids = [];

View file

@ -48,7 +48,7 @@ class LiveFeed extends Extension
return 99;
}
private function msg(string $data)
private function msg(string $data): void
{
global $config;

View file

@ -48,7 +48,7 @@ class LogConsole extends Extension
}
}
private function log(LogEvent $event)
private function log(LogEvent $event): void
{
global $config, $user;
// TODO: colour based on event->priority

View file

@ -42,7 +42,7 @@ class ShortDateTimeColumn extends DateTimeColumn
class ActorColumn extends Column
{
public function __construct($name, $title)
public function __construct(string $name, string $title)
{
parent::__construct($name, $title);
$this->sortable = false;
@ -78,6 +78,9 @@ class ActorColumn extends Column
);
}
/**
* @return array{0: string, 1: string}
*/
public function modify_input_for_read(string|array $input): array
{
list($un, $ip) = $input;
@ -90,7 +93,10 @@ class ActorColumn extends Column
return [$un, $ip];
}
public function display($row): HTMLElement
/**
* @param array{username: string, address: string} $row
*/
public function display(array $row): HTMLElement
{
$ret = emptyHTML();
if ($row['username'] != "Anonymous") {
@ -189,7 +195,7 @@ class MessageColumn extends Column
return SPAN(["style" => "color: $c"], rawHTML($this->scan_entities($row[$this->name])));
}
protected function scan_entities(string $line)
protected function scan_entities(string $line): string
{
$line = preg_replace_callback("/Image #(\d+)/s", [$this, "link_image"], $line);
$line = preg_replace_callback("/Post #(\d+)/s", [$this, "link_image"], $line);
@ -197,7 +203,10 @@ class MessageColumn extends Column
return $line;
}
protected function link_image($id)
/**
* @param array{1: string} $id
*/
protected function link_image(array $id): string
{
$iid = int_escape($id[1]);
return "<a href='".make_link("post/view/$iid")."'>&gt;&gt;$iid</a>";

View file

@ -4,14 +4,18 @@ declare(strict_types=1);
namespace Shimmie2;
use MicroHTML\HTMLElement;
use function MicroHTML\emptyHTML;
class LogDatabaseTheme extends Themelet
{
public function display_events($table, $paginator): void
public function display_events(HTMLElement $table, HTMLElement $paginator): void
{
global $page;
$page->set_title("Event Log");
$page->set_heading("Event Log");
$page->add_block(new NavBlock());
$page->add_block(new Block("Events", $table . $paginator));
$page->add_block(new Block("Events", emptyHTML($table, $paginator)));
}
}

View file

@ -39,7 +39,10 @@ class LogLogstash extends Extension
}
}
private function send_data($data)
/**
* @param array<string, mixed> $data
*/
private function send_data(array $data): void
{
global $config;

View file

@ -31,7 +31,7 @@ class LogNet extends Extension
}
}
private function msg($data)
private function msg(string $data): void
{
global $config;
$host = $config->get_string("log_net_host");

View file

@ -298,7 +298,7 @@ class Media extends Extension
* The factor of 2.5 is simply a rough guideline.
* https://stackoverflow.com/questions/527532/reasonable-php-memory-limit-for-image-resize
*
* @param array $info The output of getimagesize() for the source file in question.
* @param array{0:int,1:int,2:int,bits?:int,channels?:int} $info The output of getimagesize() for the source file in question.
* @return int The number of bytes an image resize operation is estimated to use.
*/
public static function calc_memory_use(array $info): int
@ -368,8 +368,10 @@ class Media extends Extension
return $ok;
}
public static function get_ffprobe_data($filename): array
/**
* @return array<string, mixed>
*/
public static function get_ffprobe_data(string $filename): array
{
global $config;
@ -410,7 +412,7 @@ class Media extends Extension
return $ext;
}
// private static function image_save_imagick(Imagick $image, string $path, string $format, int $output_quality = 80, bool $minimize)
// private static function image_save_imagick(Imagick $image, string $path, string $format, int $output_quality = 80, bool $minimize): void
// {
// switch ($format) {
// case FileExtension::PNG:
@ -638,7 +640,7 @@ class Media extends Extension
* Performs a resize operation on an image file using GD.
*
* @param string $image_filename The source file to be resized.
* @param array $info The output of getimagesize() for the source file.
* @param array{0:int,1:int,2:int} $info The output of getimagesize() for the source file.
* @param int $new_width
* @param int $new_height
* @param string $output_filename
@ -658,7 +660,7 @@ class Media extends Extension
string $resize_type = self::RESIZE_TYPE_FIT,
int $output_quality = 80,
bool $allow_upscale = true
) {
): void {
$width = $info[0];
$height = $info[1];
@ -785,9 +787,6 @@ class Media extends Extension
}
$background_color = Media::hex_color_allocate($new_image, $alpha_color);
if ($background_color === false) {
throw new ImageTranscodeException("Could not allocate background color");
}
if (imagefilledrectangle($new_image, 0, 0, $width, $height, $background_color) === false) {
throw new ImageTranscodeException("Could not fill background color");
}
@ -839,7 +838,7 @@ class Media extends Extension
* Determines the dimensions of a video file using ffmpeg.
*
* @param string $filename
* @return array [width, height]
* @return array{0: int, 1: int}
*/
public static function video_size(string $filename): array
{
@ -939,12 +938,14 @@ class Media extends Extension
}
}
public static function hex_color_allocate($im, $hex)
public static function hex_color_allocate(mixed $im, string $hex): int
{
$hex = ltrim($hex, '#');
$a = hexdec(substr($hex, 0, 2));
$b = hexdec(substr($hex, 2, 2));
$c = hexdec(substr($hex, 4, 2));
return imagecolorallocate($im, $a, $b, $c);
$col = imagecolorallocate($im, $a, $b, $c);
assert($col !== false);
return $col;
}
}

View file

@ -90,6 +90,8 @@ class FileExtension
/**
* Returns all the file extension associated with the specified mimetype.
*
* @return string[]
*/
public static function get_all_for_mime(string $mime): array
{

View file

@ -235,6 +235,9 @@ class MimeMap
],
];
/**
* @return array{name: string, ext: string[], mime: string[]}
*/
public static function get_for_extension(string $ext): ?array
{
$ext = strtolower($ext);
@ -247,6 +250,9 @@ class MimeMap
return null;
}
/**
* @return array{name: string, ext: string[], mime: string[]}
*/
public static function get_for_mime(string $mime): ?array
{
$mime = strtolower(MimeType::remove_parameters($mime));

View file

@ -100,6 +100,9 @@ class MimeType
return $mime;
}
/**
* @param array<string> $mime_array
*/
public static function matches_array(string $mime, array $mime_array, bool $exact = false): bool
{
// If there's an exact match, find it and that's it
@ -151,6 +154,9 @@ class MimeType
}
/**
* @param array<int|null> $comparison
*/
private static function compare_file_bytes(string $file_name, array $comparison): bool
{
$size = filesize($file_name);

View file

@ -65,7 +65,7 @@ class NotATag extends Extension
/**
* @param string[] $tags_mixed
*/
private function scan(array $tags_mixed)
private function scan(array $tags_mixed): void
{
global $database;
@ -86,6 +86,7 @@ class NotATag extends Extension
/**
* @param string[] $tags
* @return string[]
*/
private function strip(array $tags): array
{

View file

@ -4,13 +4,17 @@ declare(strict_types=1);
namespace Shimmie2;
use MicroHTML\HTMLElement;
use function MicroHTML\emptyHTML;
class NotATagTheme extends Themelet
{
public function display_untags(Page $page, $table, $paginator): void
public function display_untags(Page $page, HTMLElement $table, HTMLElement $paginator): void
{
$page->set_title("UnTags");
$page->set_heading("UnTags");
$page->add_block(new NavBlock());
$page->add_block(new Block("Edit UnTags", $table . $paginator));
$page->add_block(new Block("Edit UnTags", emptyHTML($table, $paginator)));
}
}

View file

@ -233,6 +233,8 @@ class Notes extends Extension
/**
* HERE WE GET ALL NOTES FOR DISPLAYED IMAGE.
*
* @return array<string, mixed>
*/
private function get_notes(int $imageID): array
{
@ -293,7 +295,7 @@ class Notes extends Extension
return $noteID;
}
private function add_note_request()
private function add_note_request(): void
{
global $database, $user;
@ -312,7 +314,7 @@ class Notes extends Extension
log_info("notes", "Note requested {$resultID} by {$user->name}");
}
private function update_note()
private function update_note(): void
{
global $database;
@ -331,7 +333,7 @@ class Notes extends Extension
$this->add_history(1, $note['note_id'], $note['image_id'], $note['x1'], $note['y1'], $note['height'], $note['width'], $note['note']);
}
private function delete_note()
private function delete_note(): void
{
global $user, $database;
@ -344,7 +346,7 @@ class Notes extends Extension
log_info("notes", "Note deleted {$note["note_id"]} by {$user->name}");
}
private function nuke_notes()
private function nuke_notes(): void
{
global $database, $user;
$image_id = int_escape($_POST["image_id"]);
@ -352,7 +354,7 @@ class Notes extends Extension
log_info("notes", "Notes deleted from {$image_id} by {$user->name}");
}
private function nuke_requests()
private function nuke_requests(): void
{
global $database, $user;
$image_id = int_escape($_POST["image_id"]);
@ -362,7 +364,7 @@ class Notes extends Extension
log_info("notes", "Requests deleted from {$image_id} by {$user->name}");
}
private function get_notes_list(PageRequestEvent $event)
private function get_notes_list(PageRequestEvent $event): void
{
global $database, $config;
@ -380,7 +382,7 @@ class Notes extends Extension
['enable' => 1, 'offset' => $pageNumber * $notesPerPage, 'limit' => $notesPerPage]
);
$totalPages = ceil($database->get_one("SELECT COUNT(DISTINCT image_id) FROM notes") / $notesPerPage);
$totalPages = (int)ceil($database->get_one("SELECT COUNT(DISTINCT image_id) FROM notes") / $notesPerPage);
$images = [];
while ($row = $result->fetch()) {
@ -390,7 +392,7 @@ class Notes extends Extension
$this->theme->display_note_list($images, $pageNumber + 1, $totalPages);
}
private function get_notes_requests(PageRequestEvent $event)
private function get_notes_requests(PageRequestEvent $event): void
{
global $config, $database;
@ -398,10 +400,8 @@ class Notes extends Extension
$requestsPerPage = $config->get_int('notesRequestsPerPage');
//$result = $database->get_all("SELECT * FROM pool_images WHERE pool_id=:pool_id", ['pool_id'=>$poolID]);
$result = $database->execute(
"
SELECT DISTINCT image_id
@ -410,7 +410,7 @@ class Notes extends Extension
["offset" => $pageNumber * $requestsPerPage, "limit" => $requestsPerPage]
);
$totalPages = ceil($database->get_one("SELECT COUNT(*) FROM note_request") / $requestsPerPage);
$totalPages = (int)ceil($database->get_one("SELECT COUNT(*) FROM note_request") / $requestsPerPage);
$images = [];
while ($row = $result->fetch()) {
@ -420,7 +420,7 @@ class Notes extends Extension
$this->theme->display_note_requests($images, $pageNumber + 1, $totalPages);
}
private function add_history($noteEnable, $noteID, $imageID, $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText)
private function add_history(int $noteEnable, int $noteID, int $imageID, int $noteX1, int $noteY1, int $noteHeight, int $noteWidth, string $noteText): void
{
global $user, $database;
@ -437,7 +437,7 @@ class Notes extends Extension
);
}
private function get_histories(PageRequestEvent $event)
private function get_histories(PageRequestEvent $event): void
{
global $config, $database;
@ -455,12 +455,12 @@ class Notes extends Extension
['offset' => $pageNumber * $historiesPerPage, 'limit' => $historiesPerPage]
);
$totalPages = ceil($database->get_one("SELECT COUNT(*) FROM note_histories") / $historiesPerPage);
$totalPages = (int)ceil($database->get_one("SELECT COUNT(*) FROM note_histories") / $historiesPerPage);
$this->theme->display_histories($histories, $pageNumber + 1, $totalPages);
}
private function get_history(PageRequestEvent $event)
private function get_history(PageRequestEvent $event): void
{
global $config, $database;
@ -479,7 +479,7 @@ class Notes extends Extension
['note_id' => $noteID, 'offset' => $pageNumber * $historiesPerPage, 'limit' => $historiesPerPage]
);
$totalPages = ceil($database->get_one("SELECT COUNT(*) FROM note_histories WHERE note_id = :note_id", ['note_id' => $noteID]) / $historiesPerPage);
$totalPages = (int)ceil($database->get_one("SELECT COUNT(*) FROM note_histories WHERE note_id = :note_id", ['note_id' => $noteID]) / $historiesPerPage);
$this->theme->display_history($histories, $pageNumber + 1, $totalPages);
}
@ -487,7 +487,7 @@ class Notes extends Extension
/**
* HERE GO BACK IN HISTORY AND SET THE OLD NOTE. IF WAS REMOVED WE RE-ADD IT.
*/
private function revert_history(int $noteID, int $reviewID)
private function revert_history(int $noteID, int $reviewID): void
{
global $database;

View file

@ -8,6 +8,10 @@ use MicroHTML\HTMLElement;
use function MicroHTML\INPUT;
/**
* @phpstan-type NoteHistory array{image_id:int,note_id:int,review_id:int,user_name:string,note:string,date:string}
* @phpstan-type Note array{id:int,x1:int,y1:int,height:int,width:int,note:string}
*/
class NotesTheme extends Themelet
{
public function note_button(int $image_id): HTMLElement
@ -52,6 +56,9 @@ class NotesTheme extends Themelet
}
// check action POST on form
/**
* @param Note[] $recovered_notes
*/
public function display_note_system(Page $page, int $image_id, array $recovered_notes, bool $adminOptions): void
{
$to_json = [];
@ -73,8 +80,10 @@ class NotesTheme extends Themelet
</script>");
}
public function display_note_list($images, $pageNumber, $totalPages): void
/**
* @param array<array{0:Image}> $images
*/
public function display_note_list(array $images, int $pageNumber, int $totalPages): void
{
global $page;
$pool_images = '';
@ -94,7 +103,10 @@ class NotesTheme extends Themelet
$page->add_block(new Block("Notes", $pool_images, "main", 20));
}
public function display_note_requests($images, $pageNumber, $totalPages): void
/**
* @param array<array{0:Image}> $images
*/
public function display_note_requests(array $images, int $pageNumber, int $totalPages): void
{
global $page;
@ -115,6 +127,9 @@ class NotesTheme extends Themelet
$page->add_block(new Block("Note Requests", $pool_images, "main", 20));
}
/**
* @param NoteHistory[] $histories
*/
private function get_history(array $histories): string
{
global $user;
@ -157,7 +172,10 @@ class NotesTheme extends Themelet
return $html;
}
public function display_histories($histories, $pageNumber, $totalPages): void
/**
* @param NoteHistory[] $histories
*/
public function display_histories(array $histories, int $pageNumber, int $totalPages): void
{
global $page;
@ -170,7 +188,10 @@ class NotesTheme extends Themelet
$this->display_paginator($page, "note/updated", null, $pageNumber, $totalPages);
}
public function display_history($histories, $pageNumber, $totalPages): void
/**
* @param NoteHistory[] $histories
*/
public function display_history(array $histories, int $pageNumber, int $totalPages): void
{
global $page;

View file

@ -33,8 +33,8 @@ class NumericScoreVote
public static function score(Image $post): int
{
global $database;
if ($post->score ?? null) {
return $post->score;
if ($post['score'] ?? null) {
return $post['score'];
}
return $database->get_one(
"SELECT sum(score) FROM numeric_score_votes WHERE image_id=:image_id",
@ -42,6 +42,9 @@ class NumericScoreVote
) ?? 0;
}
/**
* @return NumericScoreVote[]
*/
#[Field(extends: "Post", type: "[NumericScoreVote!]!")]
public static function votes(Image $post): array
{
@ -253,7 +256,7 @@ class NumericScore extends Extension
$this->delete_votes_by($event->id);
}
public function delete_votes_by(int $user_id)
public function delete_votes_by(int $user_id): void
{
global $database;
@ -405,7 +408,7 @@ class NumericScore extends Extension
}
}
private function add_vote(int $image_id, int $user_id, int $score)
private function add_vote(int $image_id, int $user_id, int $score): void
{
global $database;
$database->execute(

View file

@ -6,7 +6,7 @@ namespace Shimmie2;
class NumericScoreTheme extends Themelet
{
public function get_voter(Image $image)
public function get_voter(Image $image): void
{
global $user, $page;
$i_image_id = $image->id;
@ -55,7 +55,7 @@ class NumericScoreTheme extends Themelet
$page->add_block(new Block("Post Score", $html, "left", 20));
}
public function get_nuller(User $duser)
public function get_nuller(User $duser): void
{
global $user, $page;
$html = "
@ -68,7 +68,11 @@ class NumericScoreTheme extends Themelet
$page->add_block(new Block("Votes", $html, "main", 80));
}
public function view_popular($images, $dte)
/**
* @param Image[] $images
* @param string[] $dte
*/
public function view_popular(array $images, array $dte): void
{
global $page, $config;

View file

@ -22,6 +22,7 @@ class _SafeOuroborosImage
* Post Meta
*/
public ?int $change = null;
/** @var array{n:int,s:int,json_class:string} */
public ?array $created_at = null;
public ?int $id = null;
public ?int $parent_id = null;
@ -103,7 +104,8 @@ class _SafeOuroborosImage
class OuroborosPost extends _SafeOuroborosImage
{
public array $file = [];
/** @var array{tmp_name:string,name:string} */
public ?array $file = null;
public bool $is_rating_locked = false;
public bool $is_note_locked = false;
@ -111,6 +113,8 @@ class OuroborosPost extends _SafeOuroborosImage
* Initialize an OuroborosPost for creation
* Mainly just acts as a wrapper and validation layer
* @noinspection PhpMissingParentConstructorInspection
*
* @param array<string,mixed> $post
*/
public function __construct(array $post)
{
@ -184,6 +188,9 @@ class _SafeOuroborosTag
public string $name = '';
public int $type = 0;
/**
* @param array{id:int,tag:string,count:int} $tag
*/
public function __construct(array $tag)
{
$this->count = $tag['count'];
@ -319,7 +326,7 @@ class OuroborosAPI extends Extension
/**
* Wrapper for post creation
*/
protected function postCreate(OuroborosPost $post, ?string $md5 = '')
protected function postCreate(OuroborosPost $post, ?string $md5 = ''): void
{
global $config, $database;
$handler = $config->get_string(ImageConfig::UPLOAD_COLLISION_HANDLER);
@ -397,7 +404,7 @@ class OuroborosAPI extends Extension
/**
* Wrapper for getting a single post
*/
protected function postShow(int $id = null)
protected function postShow(int $id = null): void
{
if (!is_null($id)) {
$post = new _SafeOuroborosImage(Image::by_id($id));
@ -411,7 +418,7 @@ class OuroborosAPI extends Extension
* Wrapper for getting a list of posts
* @param string[] $tags
*/
protected function postIndex(int $limit, int $page, array $tags)
protected function postIndex(int $limit, int $page, array $tags): void
{
$start = ($page - 1) * $limit;
$results = Search::find_images(max($start, 0), min($limit, 100), $tags);
@ -429,7 +436,7 @@ class OuroborosAPI extends Extension
* Tag
*/
protected function tagIndex(int $limit, int $page, string $order, int $id, int $after_id, string $name, string $name_pattern)
protected function tagIndex(int $limit, int $page, string $order, int $id, int $after_id, string $name, string $name_pattern): void
{
global $database, $config;
$start = ($page - 1) * $limit;
@ -476,7 +483,7 @@ class OuroborosAPI extends Extension
/**
* Sends a simple {success,reason} message to browser
*/
private function sendResponse(int $code = 200, string $reason = '', bool $location = false)
private function sendResponse(int $code = 200, string $reason = '', bool $location = false): void
{
global $page;
if ($code == 200) {
@ -529,7 +536,10 @@ class OuroborosAPI extends Extension
$page->set_data($response);
}
private function sendData(string $type = '', array $data = [], int $offset = 0)
/**
* @param list<_SafeOuroborosTag>|list<_SafeOuroborosImage> $data
*/
private function sendData(string $type = '', array $data = [], int $offset = 0): void
{
global $page;
$response = '';
@ -539,22 +549,20 @@ class OuroborosAPI extends Extension
$xml = new \XMLWriter();
$xml->openMemory();
$xml->startDocument('1.0', 'utf-8');
if (array_key_exists(0, $data)) {
$xml->startElement($type . 's');
if ($type == 'post') {
$xml->writeAttribute('count', (string)count($data));
$xml->writeAttribute('offset', (string)$offset);
}
if ($type == 'tag') {
$xml->writeAttribute('type', 'array');
}
foreach ($data as $item) {
$this->createItemXML($xml, $type, $item);
}
$xml->endElement();
} else {
$this->createItemXML($xml, $type, $data);
$xml->startElement($type . 's');
if ($type == 'post') {
$xml->writeAttribute('count', (string)count($data));
$xml->writeAttribute('offset', (string)$offset);
}
if ($type == 'tag') {
$xml->writeAttribute('type', 'array');
}
foreach ($data as $item) {
$this->createItemXML($xml, $type, $item);
}
$xml->endElement();
$xml->endDocument();
$response = $xml->outputMemory(true);
unset($xml);
@ -562,10 +570,10 @@ class OuroborosAPI extends Extension
$page->set_data($response);
}
private function createItemXML(\XMLWriter $xml, string $type, $item)
private function createItemXML(\XMLWriter $xml, string $type, _SafeOuroborosTag|_SafeOuroborosImage $item): void
{
$xml->startElement($type);
foreach ($item as $key => $val) {
foreach (json_decode(json_encode($item)) as $key => $val) {
if ($key == 'created_at' && $type == 'post') {
$xml->writeAttribute($key, $val['s']);
} else {
@ -584,7 +592,7 @@ class OuroborosAPI extends Extension
* Currently checks for either user & session in request or cookies
* and initializes a global User
*/
private function tryAuth()
private function tryAuth(): void
{
global $config, $user;

View file

@ -70,6 +70,9 @@ class PM
$this->is_read = $is_read;
}
/**
* @param array<string, mixed> $row
*/
public static function from_row(array $row): PM
{
$pm = new PM(
@ -85,6 +88,9 @@ class PM
return $pm;
}
/**
* @return PM[]|null
*/
#[Field(extends: "User", name: "private_messages", type: "[PrivateMessage!]")]
public static function get_pms(User $duser): ?array
{
@ -299,7 +305,7 @@ class PrivMsg extends Extension
log_info("pm", "Sent PM to User #{$event->pm->to_id}");
}
private function count_pms(User $user)
private function count_pms(User $user): int
{
global $database;

View file

@ -6,7 +6,10 @@ namespace Shimmie2;
class PrivMsgTheme extends Themelet
{
public function display_pms(Page $page, $pms): void
/**
* @param PM[] $pms
*/
public function display_pms(Page $page, array $pms): void
{
global $user;
@ -58,7 +61,7 @@ class PrivMsgTheme extends Themelet
$page->add_block(new Block("Private Messages", $html, "main", 40, "private-messages"));
}
public function display_composer(Page $page, User $from, User $to, $subject = ""): void
public function display_composer(Page $page, User $from, User $to, string $subject = ""): void
{
global $user;
$post_url = make_link("pm/send");

View file

@ -26,8 +26,12 @@ class PoolCreationException extends SCoreException
class PoolAddPostsEvent extends Event
{
public int $pool_id;
/** @var int[] */
public array $posts = [];
/**
* @param int[] $posts
*/
public function __construct(int $pool_id, array $posts)
{
parent::__construct();
@ -82,6 +86,9 @@ class Pool
public string $date;
public int $posts;
/**
* @param array<string,mixed> $row
*/
public function __construct(array $row)
{
$this->id = (int)$row['id'];
@ -94,12 +101,15 @@ class Pool
$this->posts = (int)$row['posts'];
}
/**
* @param array<string,mixed> $row
*/
public static function makePool(array $row): Pool
{
return new Pool($row);
}
public static function get_pool_id_by_title($poolTitle): ?int
public static function get_pool_id_by_title(string $poolTitle): ?int
{
global $database;
$row = $database->get_row("SELECT * FROM pools WHERE title=:title", ["title" => $poolTitle]);
@ -632,7 +642,7 @@ class Pools extends Extension
);
}
private function list_pools(Page $page, int $pageNumber, $search)
private function list_pools(Page $page, int $pageNumber, ?string $search): void
{
global $config, $database;
@ -767,46 +777,43 @@ class Pools extends Extension
/**
* Gets the previous and next successive images from a pool, given a pool ID and an image ID.
*
* @return int[] Array returning two elements (prev, next) in 1 dimension. Each returns ImageID or NULL if none.
* @return array{prev:?int,next:?int} Array returning two elements (prev, next) in 1 dimension. Each returns ImageID or NULL if none.
*/
private function get_nav_posts(Pool $pool, int $imageID): ?array
private function get_nav_posts(Pool $pool, int $imageID): array
{
global $database;
if (empty($imageID)) {
return null;
}
return $database->get_row(
"
SELECT (
SELECT image_id
FROM pool_images
WHERE pool_id = :pid
AND image_order < (
SELECT image_order
FROM pool_images
WHERE pool_id = :pid
AND image_id = :iid
LIMIT 1
)
ORDER BY image_order DESC LIMIT 1
) AS prev,
(
SELECT image_id
FROM pool_images
WHERE pool_id = :pid
AND image_order > (
SELECT image_order
FROM pool_images
WHERE pool_id = :pid
AND image_id = :iid
LIMIT 1
)
ORDER BY image_order ASC LIMIT 1
) AS next
SELECT (
SELECT image_id
FROM pool_images
WHERE pool_id = :pid
AND image_order < (
SELECT image_order
FROM pool_images
WHERE pool_id = :pid
AND image_id = :iid
LIMIT 1
)
ORDER BY image_order DESC LIMIT 1
) AS prev,
(
SELECT image_id
FROM pool_images
WHERE pool_id = :pid
AND image_order > (
SELECT image_order
FROM pool_images
WHERE pool_id = :pid
AND image_id = :iid
LIMIT 1
)
ORDER BY image_order ASC LIMIT 1
) AS next
LIMIT 1",
LIMIT 1
",
["pid" => $pool->id, "iid" => $imageID]
);
}
@ -814,7 +821,7 @@ class Pools extends Extension
/**
* Retrieve all the images in a pool, given a pool ID.
*/
private function get_posts(PageRequestEvent $event, int $poolID)
private function get_posts(PageRequestEvent $event, int $poolID): void
{
global $config, $user, $database;
@ -885,7 +892,7 @@ class Pools extends Extension
*
* $action Action=1 (one) MEANS ADDED, Action=0 (zero) MEANS REMOVED
*/
private function add_history(int $poolID, int $action, string $images, int $count)
private function add_history(int $poolID, int $action, string $images, int $count): void
{
global $user, $database;
@ -897,7 +904,7 @@ class Pools extends Extension
);
}
private function get_history(int $pageNumber)
private function get_history(int $pageNumber): void
{
global $config, $database;
@ -923,7 +930,7 @@ class Pools extends Extension
/**
* HERE GO BACK IN HISTORY AND ADD OR REMOVE POSTS TO POOL.
*/
private function revert_history(int $historyID)
private function revert_history(int $historyID): void
{
global $database;
$status = $database->get_all("SELECT * FROM pool_history WHERE id=:hid", ["hid" => $historyID]);
@ -1009,7 +1016,7 @@ class Pools extends Extension
return true;
}
private function update_count(int $pool_id)
private function update_count(int $pool_id): void
{
global $database;
$database->execute(

View file

@ -31,6 +31,9 @@ class PoolsTest extends ShimmiePHPUnitTestCase
$this->assert_title("Error");
}
/**
* @return array{0: int, 1: array{0: int, 1: int}}
*/
public function testCreate(): array
{
$this->log_in_as_user();
@ -53,7 +56,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
}
#[Depends('testCreate')]
public function testOnViewImage($args): void
public function testOnViewImage(): void
{
[$pool_id, $image_ids] = $this->testCreate();
@ -67,7 +70,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
}
#[Depends('testCreate')]
public function testSearch($args): void
public function testSearch(): void
{
[$pool_id, $image_ids] = $this->testCreate();
@ -79,7 +82,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
}
#[Depends('testCreate')]
public function testList($args): void
public function testList(): void
{
$this->testCreate();
$this->get_page("pool/list");
@ -87,7 +90,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
}
#[Depends('testCreate')]
public function testView($args): void
public function testView(): void
{
[$pool_id, $image_ids] = $this->testCreate();
@ -96,7 +99,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
}
#[Depends('testCreate')]
public function testHistory($args): void
public function testHistory(): void
{
[$pool_id, $image_ids] = $this->testCreate();
@ -105,7 +108,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
}
#[Depends('testCreate')]
public function testImport($args): void
public function testImport(): void
{
[$pool_id, $image_ids] = $this->testCreate();
@ -116,8 +119,11 @@ class PoolsTest extends ShimmiePHPUnitTestCase
$this->assert_text("Pool");
}
/**
* @return array{0: int, 1: array{0: int, 1:int}}
*/
#[Depends('testCreate')]
public function testRemovePosts($args): array
public function testRemovePosts(): array
{
[$pool_id, $image_ids] = $this->testCreate();
@ -131,9 +137,9 @@ class PoolsTest extends ShimmiePHPUnitTestCase
}
#[Depends('testRemovePosts')]
public function testAddPosts($args): void
public function testAddPosts(): void
{
[$pool_id, $image_ids] = $this->testRemovePosts(null);
[$pool_id, $image_ids] = $this->testRemovePosts();
$page = $this->post_page("pool/add_posts", [
"pool_id" => $pool_id,
@ -142,8 +148,11 @@ class PoolsTest extends ShimmiePHPUnitTestCase
$this->assertEquals(PageMode::REDIRECT, $page->mode);
}
/**
* @return array{0: int, 1: array{0: int, 1:int}}
*/
#[Depends('testCreate')]
public function testEditDescription($args): array
public function testEditDescription(): array
{
[$pool_id, $image_ids] = $this->testCreate();

View file

@ -10,13 +10,18 @@ use function MicroHTML\emptyHTML;
use function MicroHTML\rawHTML;
use function MicroHTML\{A,BR,DIV,INPUT,P,SCRIPT,SPAN,TABLE,TBODY,TD,TEXTAREA,TH,THEAD,TR};
/**
* @phpstan-type PoolHistory array{id:int,pool_id:int,title:string,user_name:string,action:string,images:string,count:int,date:string}
*/
class PoolsTheme extends Themelet
{
/**
* Adds a block to the panel with information on the pool(s) the image is in.
* $navIDs = Multidimensional array containing pool id, info & nav IDs.
*
* @param array<int,array{nav:array{prev:?int,next:?int},info:Pool}> $navIDs
*/
public function pool_info(array $navIDs)
public function pool_info(array $navIDs): void
{
global $page;
@ -25,13 +30,11 @@ class PoolsTheme extends Themelet
foreach ($navIDs as $poolID => $poolInfo) {
$div = DIV(SHM_A("pool/view/" . $poolID, $poolInfo["info"]->title));
if (!empty($poolInfo["nav"])) {
if (!empty($poolInfo["nav"]["prev"])) {
$div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["prev"], "Prev", class: "pools_prev_img"));
}
if (!empty($poolInfo["nav"]["next"])) {
$div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["next"], "Next", class: "pools_next_img"));
}
if (!empty($poolInfo["nav"]["prev"])) {
$div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["prev"], "Prev", class: "pools_prev_img"));
}
if (!empty($poolInfo["nav"]["next"])) {
$div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["next"], "Next", class: "pools_next_img"));
}
$linksPools->appendChild($div);
@ -42,6 +45,9 @@ class PoolsTheme extends Themelet
}
}
/**
* @param array<int, string> $pools
*/
public function get_adder_html(Image $image, array $pools): HTMLElement
{
return SHM_SIMPLE_FORM(
@ -54,8 +60,10 @@ class PoolsTheme extends Themelet
/**
* HERE WE SHOWS THE LIST OF POOLS.
*
* @param Pool[] $pools
*/
public function list_pools(Page $page, array $pools, string $search, int $pageNumber, int $totalPages)
public function list_pools(Page $page, array $pools, string $search, int $pageNumber, int $totalPages): void
{
// Build up the list of pools.
$pool_rows = [];
@ -95,7 +103,7 @@ class PoolsTheme extends Themelet
/*
* HERE WE DISPLAY THE NEW POOL COMPOSER
*/
public function new_pool_composer(Page $page)
public function new_pool_composer(Page $page): void
{
$form = SHM_SIMPLE_FORM("pool/create", TABLE(
TR(TD("Title:"), TD(INPUT(["type" => "text", "name" => "title"]))),
@ -108,7 +116,7 @@ class PoolsTheme extends Themelet
$page->add_block(new Block("Create Pool", $form, position: 20));
}
private function display_top(?Pool $pool, string $heading, bool $check_all = false)
private function display_top(?Pool $pool, string $heading, bool $check_all = false): void
{
global $page, $user;
@ -146,8 +154,10 @@ class PoolsTheme extends Themelet
/**
* HERE WE DISPLAY THE POOL WITH TITLE DESCRIPTION AND IMAGES WITH PAGINATION.
*
* @param Image[] $images
*/
public function view_pool(Pool $pool, array $images, int $pageNumber, int $totalPages)
public function view_pool(Pool $pool, array $images, int $pageNumber, int $totalPages): void
{
global $page;
@ -166,7 +176,7 @@ class PoolsTheme extends Themelet
/**
* HERE WE DISPLAY THE POOL OPTIONS ON SIDEBAR BUT WE HIDE REMOVE OPTION IF THE USER IS NOT THE OWNER OR ADMIN.
*/
public function sidebar_options(Page $page, Pool $pool, bool $check_all)
public function sidebar_options(Page $page, Pool $pool, bool $check_all): void
{
global $user;
@ -246,8 +256,10 @@ class PoolsTheme extends Themelet
/**
* HERE WE DISPLAY THE RESULT OF THE SEARCH ON IMPORT.
*
* @param Image[] $images
*/
public function pool_result(Page $page, array $images, Pool $pool)
public function pool_result(Page $page, array $images, Pool $pool): void
{
$this->display_top($pool, "Importing Posts", true);
@ -283,8 +295,10 @@ class PoolsTheme extends Themelet
/**
* HERE WE DISPLAY THE POOL ORDERER.
* WE LIST ALL IMAGES ON POOL WITHOUT PAGINATION AND WITH A TEXT INPUT TO SET A NUMBER AND CHANGE THE ORDER
*
* @param Image[] $images
*/
public function edit_order(Page $page, Pool $pool, array $images)
public function edit_order(Page $page, Pool $pool, array $images): void
{
$this->display_top($pool, "Sorting Pool");
@ -293,7 +307,7 @@ class PoolsTheme extends Themelet
$form->appendChild(SPAN(
["class" => "thumb"],
$this->build_thumb_html($image),
INPUT(["type" => "number", "name" => "imgs[$i][]", "value" => $image->image_order, "style" => "max-width: 50px;"]),
INPUT(["type" => "number", "name" => "imgs[$i][]", "value" => $image['image_order'], "style" => "max-width: 50px;"]),
INPUT(["type" => "hidden", "name" => "imgs[$i][]", "value" => $image->id])
));
}
@ -311,8 +325,10 @@ class PoolsTheme extends Themelet
*
* WE LIST ALL IMAGES ON POOL WITHOUT PAGINATION AND WITH
* A CHECKBOX TO SELECT WHICH IMAGE WE WANT TO REMOVE
*
* @param Image[] $images
*/
public function edit_pool(Page $page, Pool $pool, array $images)
public function edit_pool(Page $page, Pool $pool, array $images): void
{
$_input_id = INPUT(["type" => "hidden", "name" => "pool_id", "value" => $pool->id]);
@ -347,8 +363,10 @@ class PoolsTheme extends Themelet
/**
* HERE WE DISPLAY THE HISTORY LIST.
*
* @param PoolHistory[] $histories
*/
public function show_history(array $histories, int $pageNumber, int $totalPages)
public function show_history(array $histories, int $pageNumber, int $totalPages): void
{
global $page;
@ -397,11 +415,17 @@ class PoolsTheme extends Themelet
$this->display_paginator($page, "pool/updated", null, $pageNumber, $totalPages);
}
/**
* @param array<int,string> $options
*/
public function get_bulk_pool_selector(array $options): HTMLElement
{
return SHM_SELECT("bulk_pool_select", $options, required: true, empty_option: true);
}
/**
* @param string[] $search_terms
*/
public function get_bulk_pool_input(array $search_terms): HTMLElement
{
return INPUT(
@ -410,7 +434,7 @@ class PoolsTheme extends Themelet
"name" => "bulk_pool_new",
"placeholder" => "New Pool",
"required" => "",
"value" => implode(" ", $search_terms)
"value" => Tag::implode($search_terms)
]
);
}

View file

@ -11,7 +11,7 @@ class PostPeekInfo extends ExtensionInfo
public string $key = self::KEY;
public string $name = "Post Peek";
public string $url = self::SHIMMIE_URL;
public array $authors = ["Matthew Barbour"];
public array $authors = ["Matthew Barbour" => "matthew@darkholme.net"];
public string $license = self::LICENSE_WTFPL;
public string $description = "Peek at posts";
}

View file

@ -88,7 +88,7 @@ class PostTitles extends Extension
}
}
private function set_title(int $image_id, string $title)
private function set_title(int $image_id, string $title): void
{
global $database;
$database->execute("UPDATE images SET title=:title WHERE id=:id", ['title' => $title, 'id' => $image_id]);

View file

@ -190,7 +190,9 @@ class PrivateImage extends Extension
}
}
/**
* @param string[] $context
*/
private function no_private_query(array $context): bool
{
foreach ($context as $term) {
@ -201,7 +203,7 @@ class PrivateImage extends Extension
return true;
}
public static function privatize_image($image_id)
public static function privatize_image(int $image_id): void
{
global $database;
@ -211,7 +213,7 @@ class PrivateImage extends Extension
);
}
public static function publicize_image($image_id)
public static function publicize_image(int $image_id): void
{
global $database;

View file

@ -6,7 +6,7 @@ namespace Shimmie2;
class QRImageTheme extends Themelet
{
public function links_block(string $link)
public function links_block(string $link): void
{
global $page;

View file

@ -6,12 +6,13 @@ namespace Shimmie2;
class RandomListTheme extends Themelet
{
/** @var string[] */
protected array $search_terms;
/**
* @param string[] $search_terms
*/
public function set_page(array $search_terms)
public function set_page(array $search_terms): void
{
$this->search_terms = $search_terms;
}
@ -42,6 +43,9 @@ class RandomListTheme extends Themelet
$page->add_block(new Block("Navigation", $nav, "left", 0));
}
/**
* @param string[] $search_terms
*/
protected function build_navigation(array $search_terms): string
{
$h_search_string = html_escape(Tag::implode($search_terms));

View file

@ -410,6 +410,9 @@ class Ratings extends Extension
}
}
/**
* @return ImageRating[]
*/
public static function get_sorted_ratings(): array
{
global $_shm_ratings;
@ -421,6 +424,10 @@ class Ratings extends Extension
return $ratings;
}
/**
* @param ImageRating[]|null $ratings
* @return array<string, string>
*/
public static function get_ratings_dict(array $ratings = null): array
{
if (!isset($ratings)) {
@ -464,6 +471,9 @@ class Ratings extends Extension
return array_intersect($available, $selected);
}
/**
* @param string[] $privs
*/
public static function privs_to_sql(array $privs): string
{
$arr = [];
@ -566,7 +576,7 @@ class Ratings extends Extension
}
}
private function set_rating(int $image_id, string $rating, string $old_rating)
private function set_rating(int $image_id, string $rating, string $old_rating): void
{
global $database;
if ($old_rating != $rating) {

View file

@ -11,6 +11,10 @@ use function MicroHTML\{A,P,TABLE,TD,TH,TR};
class RatingsTheme extends Themelet
{
/**
* @param array<string, ImageRating> $ratings
* @param string[] $selected_options
*/
public function get_selection_rater_html(string $name = "rating", array $ratings = [], array $selected_options = []): HTMLElement
{
return SHM_SELECT($name, !empty($ratings) ? $ratings : Ratings::get_ratings_dict(), required: true, selected_options: $selected_options);
@ -25,6 +29,9 @@ class RatingsTheme extends Themelet
);
}
/**
* @param ImageRating[] $current_ratings
*/
public function display_form(array $current_ratings): void
{
global $page;
@ -39,6 +46,9 @@ class RatingsTheme extends Themelet
$page->add_block(new Block("Update Ratings", SHM_SIMPLE_FORM("admin/update_ratings", $table)));
}
/**
* @param ImageRating[] $ratings
*/
public function get_help_html(array $ratings): HTMLElement
{
$rating_rows = [TR(TH("Name"), TH("Search Term"), TH("Abbreviation"))];

View file

@ -169,6 +169,9 @@ class Relationships extends Extension
}
}
/**
* @return Image[]
*/
public static function get_children(Image $image, int $omit = null): array
{
global $database;
@ -183,7 +186,7 @@ class Relationships extends Extension
return $output;
}
private function remove_parent(int $imageID)
private function remove_parent(int $imageID): void
{
global $database;
$parentID = $database->get_one("SELECT parent_id FROM images WHERE id = :iid", ["iid" => $imageID]);
@ -194,7 +197,7 @@ class Relationships extends Extension
}
}
private function set_has_children(int $parent_id)
private function set_has_children(int $parent_id): void
{
global $database;

View file

@ -12,6 +12,9 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
// Set by box
//=================================================================
/**
* @return array{0: Image, 1: Image, 2: Image}
*/
public function testNoParent(): array
{
$this->log_in_as_user();
@ -34,8 +37,11 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
return [$image_1, $image_2, $image_3];
}
/**
* @return array{0:Image, 1:Image, 2:Image}
*/
#[Depends('testNoParent')]
public function testSetParent($imgs): array
public function testSetParent(): array
{
[$image_1, $image_2, $image_3] = $this->testNoParent();
@ -56,10 +62,13 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
return [$image_1, $image_2, $image_3];
}
/**
* @return array{0:Image, 1:Image, 2:Image}
*/
#[Depends('testSetParent')]
public function testChangeParent($imgs): array
public function testChangeParent(): array
{
[$image_1, $image_2, $image_3] = $this->testSetParent(null);
[$image_1, $image_2, $image_3] = $this->testSetParent();
send_event(new ImageRelationshipSetEvent($image_2->id, $image_3->id));
// refresh data from database
@ -78,9 +87,9 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
}
#[Depends('testSetParent')]
public function testSearch($imgs): void
public function testSearch(): void
{
[$image_1, $image_2, $image_3] = $this->testSetParent(null);
[$image_1, $image_2, $image_3] = $this->testSetParent();
$this->assert_search_results(["parent:any"], [$image_2->id]);
$this->assert_search_results(["parent:none"], [$image_3->id, $image_1->id]);
@ -91,9 +100,9 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
}
#[Depends('testChangeParent')]
public function testRemoveParent($imgs): void
public function testRemoveParent(): void
{
[$image_1, $image_2, $image_3] = $this->testChangeParent(null);
[$image_1, $image_2, $image_3] = $this->testChangeParent();
global $database;
$database->execute(
@ -119,6 +128,9 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
// Set by tag
//=================================================================
/**
* @return array{0:Image, 1:Image, 2:Image}
*/
public function testSetParentByTagBase(): array
{
$this->log_in_as_user();
@ -140,8 +152,11 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
return [$image_1, $image_2, $image_3];
}
/**
* @return array{0:Image, 1:Image, 2:Image}
*/
#[Depends('testSetParentByTagBase')]
public function testSetParentByTag($imgs): array
public function testSetParentByTag(): array
{
[$image_1, $image_2, $image_3] = $this->testSetParentByTagBase();
@ -163,10 +178,13 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
return [$image_1, $image_2, $image_3];
}
/**
* @return array{0:Image, 1:Image, 2:Image}
*/
#[Depends('testSetParentByTag')]
public function testSetChildByTag($imgs): array
public function testSetChildByTag(): array
{
[$image_1, $image_2, $image_3] = $this->testSetParentByTag(null);
[$image_1, $image_2, $image_3] = $this->testSetParentByTag();
send_event(new TagSetEvent($image_3, ["pbx", "child:{$image_1->id}"]));
@ -187,10 +205,9 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
}
#[Depends('testSetChildByTag')]
public function testRemoveParentByTag($imgs): void
public function testRemoveParentByTag(): void
{
[$image_1, $image_2, $image_3] = $this->testSetChildByTag(null);
assert(!is_null($image_3));
[$image_1, $image_2, $image_3] = $this->testSetChildByTag();
// check parent is set
$this->assertEquals($image_2['parent_id'], $image_1->id);

Some files were not shown because too many files have changed in this diff Show more