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

View file

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

View file

@ -10,7 +10,9 @@ namespace Shimmie2;
class CommandBuilder class CommandBuilder
{ {
private string $executable; private string $executable;
/** @var string[] */
private array $args = []; private array $args = [];
/** @var string[] */
public array $output; public array $output;
public function __construct(string $executable) 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. * 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; 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 * 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" * page where they can be modified, while calling get_* with a "default"
* parameter won't show up. * parameter won't show up.
*
* @param mixed[] $value
*/ */
public function set_default_array(string $name, array $value): void; 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. * 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; public function get_array(string $name, ?array $default = []): ?array;
//@} /*--------------------------------------------------------------------------------------------*/ //@} /*--------------------------------------------------------------------------------------------*/
@ -134,6 +141,7 @@ interface Config
*/ */
abstract class BaseConfig implements Config abstract class BaseConfig implements Config
{ {
/** @var array<string, mixed> */
public array $values = []; public array $values = [];
public function set_int(string $name, ?int $value): void 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 public function get_int(string $name, ?int $default = null): ?int
{ {
return (int)($this->get($name, $default)); 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 public function get_float(string $name, ?float $default = null): ?float
{ {
return (float)($this->get($name, $default)); 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 public function get_string(string $name, ?string $default = null): ?string
{ {
$val = $this->get($name, $default); $val = $this->get($name, $default);
@ -224,17 +247,34 @@ abstract class BaseConfig implements Config
return $val; return $val;
} }
/**
* @template T of bool|null
* @param T $default
* @return T|bool
*/
public function get_bool(string $name, ?bool $default = null): ?bool public function get_bool(string $name, ?bool $default = null): ?bool
{ {
return bool_escape($this->get($name, $default)); 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])) { if (isset($this->values[$name])) {
return $this->values[$name]; return $this->values[$name];

View file

@ -19,8 +19,12 @@ enum DatabaseDriverID: string
class DatabaseException extends SCoreException class DatabaseException extends SCoreException
{ {
public string $query; public string $query;
/** @var array<string, mixed> */
public array $args; public array $args;
/**
* @param array<string, mixed> $args
*/
public function __construct(string $msg, string $query, array $args) public function __construct(string $msg, string $query, array $args)
{ {
parent::__construct($msg); parent::__construct($msg);
@ -32,6 +36,8 @@ class DatabaseException extends SCoreException
/** /**
* A class for controlled database access * A class for controlled database access
*
* @phpstan-type QueryArgs array<string, string|int|bool|null>
*/ */
class Database class Database
{ {
@ -52,6 +58,7 @@ class Database
* How many queries this DB object has run * How many queries this DB object has run
*/ */
public int $query_count = 0; public int $query_count = 0;
/** @var string[] */
public array $queries = []; public array $queries = [];
public function __construct(string $dsn) public function __construct(string $dsn)
@ -162,13 +169,15 @@ class Database
return $this->get_engine()->get_version($this->get_db()); 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 private function count_time(string $method, float $start, string $query, ?array $args): void
{ {
global $_tracer, $tracer_enabled; global $_tracer, $tracer_enabled;
$dur = ftime() - $start; $dur = ftime() - $start;
// trim whitespace // trim whitespace
$query = preg_replace('/[\n\t ]/m', ' ', $query); $query = preg_replace('/[\n\t ]+/m', ' ', $query);
$query = preg_replace('/ +/m', ' ', $query);
$query = trim($query); $query = trim($query);
if ($tracer_enabled) { if ($tracer_enabled) {
$_tracer->complete($start * 1000000, $dur * 1000000, "DB Query", ["query" => $query, "args" => $args, "method" => $method]); $_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); $this->get_engine()->notify($this->get_db(), $channel, $data);
} }
/**
* @param QueryArgs $args
*/
public function _execute(string $query, array $args = []): PDOStatement public function _execute(string $query, array $args = []): PDOStatement
{ {
try { try {
@ -203,6 +215,8 @@ class Database
/** /**
* Execute an SQL query with no return * Execute an SQL query with no return
*
* @param QueryArgs $args
*/ */
public function execute(string $query, array $args = []): PDOStatement public function execute(string $query, array $args = []): PDOStatement
{ {
@ -214,6 +228,9 @@ class Database
/** /**
* Execute an SQL query and return a 2D array. * 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 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. * 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 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. * 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 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. * 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 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. * 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 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. * 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 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. * 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 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. * Execute an SQL query and return a single value, or null.
*
* @param QueryArgs $args
*/ */
public function get_one(string $query, array $args = []): mixed 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 * 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 public function exists(string $query, array $args = []): bool
{ {

View file

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

View file

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

View file

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

View file

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

View file

@ -12,9 +12,10 @@ namespace Shimmie2;
* Add a directory full of images * Add a directory full of images
* *
* @param string $base * @param string $base
* @param string[] $extra_tags
* @return UploadResult[] * @return UploadResult[]
*/ */
function add_dir(string $base, ?array $extra_tags = []): array function add_dir(string $base, array $extra_tags = []): array
{ {
global $database; global $database;
$results = []; $results = [];
@ -33,6 +34,7 @@ function add_dir(string $base, ?array $extra_tags = []): array
])); ]));
$results = []; $results = [];
foreach($dae->images as $image) { foreach($dae->images as $image) {
assert(!is_null($image->id));
$results[] = new UploadSuccess($filename, $image->id); $results[] = new UploadSuccess($filename, $image->id);
} }
return $results; return $results;
@ -59,7 +61,7 @@ function get_file_ext(string $filename): ?string
* @param int $orig_width * @param int $orig_width
* @param int $orig_height * @param int $orig_height
* @param bool $use_dpi_scaling Enables the High-DPI scaling. * @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 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 function get_scaled_by_aspect_ratio(int $original_width, int $original_height, int $max_width, int $max_height): array
{ {
$xscale = ($max_width / $original_width); $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. * 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 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( function create_scaled_image(
string $inname, string $inname,
string $outname, string $outname,

View file

@ -86,7 +86,8 @@ class TagUsage
*/ */
class Tag 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 public static function get_or_create_id(string $tag): int
{ {
@ -196,9 +197,13 @@ class Tag
public static function sanitize(string $tag): string public static function sanitize(string $tag): string
{ {
$tag = preg_replace("/\s/", "", $tag); # whitespace $tag = preg_replace("/\s/", "", $tag); # whitespace
assert($tag !== null);
$tag = preg_replace('/\x20[\x0e\x0f]/', '', $tag); # unicode RTL $tag = preg_replace('/\x20[\x0e\x0f]/', '', $tag); # unicode RTL
assert($tag !== null);
$tag = preg_replace("/\.+/", ".", $tag); # strings of dots? $tag = preg_replace("/\.+/", ".", $tag); # strings of dots?
assert($tag !== null);
$tag = preg_replace("/^(\.+[\/\\\\])+/", "", $tag); # trailing slashes? $tag = preg_replace("/^(\.+[\/\\\\])+/", "", $tag); # trailing slashes?
assert($tag !== null);
$tag = trim($tag, ", \t\n\r\0\x0B"); $tag = trim($tag, ", \t\n\r\0\x0B");
if ($tag == ".") { if ($tag == ".") {
@ -211,6 +216,10 @@ class Tag
return $tag; return $tag;
} }
/**
* @param string[] $tags1
* @param string[] $tags2
*/
public static function compare(array $tags1, array $tags2): bool public static function compare(array $tags1, array $tags2): bool
{ {
if (count($tags1) !== count($tags2)) { if (count($tags1) !== count($tags2)) {
@ -225,6 +234,11 @@ class Tag
return $tags1 == $tags2; return $tags1 == $tags2;
} }
/**
* @param string[] $source
* @param string[] $remove
* @return string[]
*/
public static function get_diff_tags(array $source, array $remove): array public static function get_diff_tags(array $source, array $remove): array
{ {
$before = array_map('strtolower', $source); $before = array_map('strtolower', $source);
@ -238,6 +252,10 @@ class Tag
return $after; return $after;
} }
/**
* @param string[] $tags
* @return string[]
*/
public static function sanitize_array(array $tags): array public static function sanitize_array(array $tags): array
{ {
global $page; 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 = SHM_FORM($target);
$form->appendChild(emptyHTML(...$children)); $form->appendChild(emptyHTML(...$children));
return $form; return $form;
} }
/**
* @param array<string, mixed> $args
*/
function SHM_SUBMIT(string $text, array $args = []): HTMLElement function SHM_SUBMIT(string $text, array $args = []): HTMLElement
{ {
$args["type"] = "submit"; $args["type"] = "submit";
@ -60,6 +66,9 @@ function SHM_SUBMIT(string $text, array $args = []): HTMLElement
return INPUT($args); return INPUT($args);
} }
/**
* @param array<string, mixed> $args
*/
function SHM_A(string $href, string|HTMLElement $text, string $id = "", string $class = "", array $args = []): HTMLElement function SHM_A(string $href, string|HTMLElement $text, string $id = "", string $class = "", array $args = []): HTMLElement
{ {
$args["href"] = make_link($href); $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)) { if (is_string($foot)) {
$foot = TFOOT(TR(TD(["colspan" => "2"], INPUT(["type" => "submit", "value" => $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. * Generates a <select> element and sets up the given options.
* *
* @param string $name The name attribute of <select>. * @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<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 $selected_options The values of options that should be pre-selected. * @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 $required Wether the <select> element is required.
* @param bool $multiple Wether the <select> element is multiple-choice. * @param bool $multiple Wether the <select> element is multiple-choice.
* @param bool $empty_option Whether the first option should be an empty one. * @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 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 * Return the unique elements of an array, case insensitively
*
* @param array<string> $array
* @return list<string>
*/ */
function array_iunique(array $array): array 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 a list of all the regular files in a directory and subdirectories
*
* @return string[]
*/ */
function list_files(string $base, string $_sub_dir = ""): array 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. * 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. * 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 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')) { if (!function_exists('mb_strlen')) {
// TODO: we should warn the admin that they are missing multibyte support // TODO: we should warn the admin that they are missing multibyte support
/** @noinspection PhpUnusedParameterInspection */ /** @noinspection PhpUnusedParameterInspection */
function mb_strlen($str, $encoding): int function mb_strlen(string $str, string $encoding): int
{ {
return strlen($str); 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); return strtolower($str);
} }
} }
/** @noinspection PhpUnhandledExceptionInspection */ /**
* @return class-string[]
*/
function get_subclasses_of(string $parent): array function get_subclasses_of(string $parent): array
{ {
$result = []; $result = [];
@ -307,6 +316,8 @@ function get_base_href(): string
/** /**
* The opposite of the standard library's parse_url * The opposite of the standard library's parse_url
*
* @param array<string, string|int> $parsed_url
*/ */
function unparse_url(array $parsed_url): string 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 * 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... Sometimes, I don't like PHP -- this, is one of those times...
@ -634,6 +645,10 @@ function isValidDate(string $date): bool
return false; return false;
} }
/**
* @param array<string, string> $inputs
* @return array<string, mixed>
*/
function validate_input(array $inputs): array function validate_input(array $inputs): array
{ {
$outputs = []; $outputs = [];
@ -754,6 +769,12 @@ function join_path(string ...$paths): string
/** /**
* Perform callback on each item returned by an iterator. * 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 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. * 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 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); 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 function _dump_event_listeners(array $event_listeners, string $path): void
{ {
$p = "<"."?php\nnamespace Shimmie2;\n"; $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); $scn = _namespaced_class_name($class);
$p .= "\$$scn = new $scn(); "; $p .= "\$$scn = new $scn(); ";
} }

View file

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

View file

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

View file

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

View file

@ -23,8 +23,13 @@ class UserClass
#[Field] #[Field]
public ?string $name = null; public ?string $name = null;
public ?UserClass $parent = null; public ?UserClass $parent = null;
/** @var array<string, bool> */
public array $abilities = []; public array $abilities = [];
/**
* @param array<string, bool> $abilities
*/
public function __construct(string $name, string $parent = null, array $abilities = []) public function __construct(string $name, string $parent = null, array $abilities = [])
{ {
global $_shm_user_classes; global $_shm_user_classes;
@ -39,6 +44,9 @@ class UserClass
$_shm_user_classes[$name] = $this; $_shm_user_classes[$name] = $this;
} }
/**
* @return string[]
*/
#[Field(type: "[Permission!]!")] #[Field(type: "[Permission!]!")]
public function permissions(): array 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 $tmpl;
} }
/**
* @return null|array<string, mixed>
*/
function fetch_url(string $url, string $mfile): ?array function fetch_url(string $url, string $mfile): ?array
{ {
global $config; global $config;
if ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "curl" && function_exists("curl_init")) { if ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "curl" && function_exists("curl_init")) {
$ch = curl_init($url); $ch = curl_init($url);
assert($ch !== false);
$fp = fopen($mfile, "w"); $fp = fopen($mfile, "w");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
@ -397,6 +401,9 @@ function path_to_tags(string $path): array
return $tags; return $tags;
} }
/**
* @return string[]
*/
function get_dir_contents(string $dir): array function get_dir_contents(string $dir): array
{ {
assert(!empty($dir)); assert(!empty($dir));
@ -442,7 +449,9 @@ function remove_empty_dirs(string $dir): bool
return $result; return $result;
} }
/**
* @return string[]
*/
function get_files_recursively(string $dir): array function get_files_recursively(string $dir): array
{ {
assert(!empty($dir)); assert(!empty($dir));
@ -475,6 +484,8 @@ function get_files_recursively(string $dir): array
/** /**
* Returns amount of files & total size of dir. * Returns amount of files & total size of dir.
*
* @return array{"path": string, "total_files": int, "total_mb": string}
*/ */
function scan_dir(string $path): array function scan_dir(string $path): array
{ {

View file

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

View file

@ -174,7 +174,9 @@ class Approval extends Extension
} }
} }
/**
* @param string[] $context
*/
private function no_approval_query(array $context): bool private function no_approval_query(array $context): bool
{ {
foreach ($context as $term) { foreach ($context as $term) {
@ -185,7 +187,7 @@ class Approval extends Extension
return true; return true;
} }
public static function approve_image($image_id) public static function approve_image(int $image_id): void
{ {
global $database, $user; 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; 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]); 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; global $database;
$database->execute("DELETE FROM artist_alias WHERE id = :id", ['id' => $aliasID]); $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; global $database;
$database->execute("DELETE FROM artist_urls WHERE id = :id", ['id' => $urlID]); $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; global $database;
$database->execute("DELETE FROM artist_members WHERE id = :id", ['id' => $memberID]); $database->execute("DELETE FROM artist_members WHERE id = :id", ['id' => $memberID]);
} }
/**
* @return array<string, mixed>
*/
private function get_alias_by_id(int $aliasID): array private function get_alias_by_id(int $aliasID): array
{ {
global $database; global $database;
return $database->get_row("SELECT * FROM artist_alias WHERE id = :id", ['id' => $aliasID]); 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 private function get_url_by_id(int $urlID): array
{ {
global $database; global $database;
return $database->get_row("SELECT * FROM artist_urls WHERE id = :id", ['id' => $urlID]); 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 private function get_member_by_id(int $memberID): array
{ {
global $database; global $database;
return $database->get_row("SELECT * FROM artist_members WHERE id = :id", ['id' => $memberID]); return $database->get_row("SELECT * FROM artist_members WHERE id = :id", ['id' => $memberID]);
} }
private function update_artist() private function update_artist(): void
{ {
global $user; global $user;
$inputs = validate_input([ $inputs = validate_input([
@ -629,7 +638,7 @@ class Artists extends Extension
} }
} }
private function update_alias() private function update_alias(): void
{ {
global $user; global $user;
$inputs = validate_input([ $inputs = validate_input([
@ -639,7 +648,7 @@ class Artists extends Extension
$this->save_existing_alias($inputs['aliasID'], $inputs['alias'], $user->id); $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; global $database;
$database->execute( $database->execute(
@ -648,7 +657,7 @@ class Artists extends Extension
); );
} }
private function update_url() private function update_url(): void
{ {
global $user; global $user;
$inputs = validate_input([ $inputs = validate_input([
@ -658,7 +667,7 @@ class Artists extends Extension
$this->save_existing_url($inputs['urlID'], $inputs['url'], $user->id); $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; global $database;
$database->execute( $database->execute(
@ -667,7 +676,7 @@ class Artists extends Extension
); );
} }
private function update_member() private function update_member(): void
{ {
global $user; global $user;
$inputs = validate_input([ $inputs = validate_input([
@ -677,7 +686,7 @@ class Artists extends Extension
$this->save_existing_member($inputs['memberID'], $inputs['name'], $user->id); $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; global $database;
$database->execute( $database->execute(
@ -772,6 +781,9 @@ class Artists extends Extension
return ($result != 0); return ($result != 0);
} }
/**
* @return array<string, mixed>
*/
private function get_artist(int $artistID): array private function get_artist(int $artistID): array
{ {
global $database; global $database;
@ -786,6 +798,9 @@ class Artists extends Extension
return $result; return $result;
} }
/**
* @return array<string, mixed>
*/
private function get_members(int $artistID): array private function get_members(int $artistID): array
{ {
global $database; global $database;
@ -802,6 +817,9 @@ class Artists extends Extension
return $result; return $result;
} }
/**
* @return array<string, mixed>
*/
private function get_urls(int $artistID): array private function get_urls(int $artistID): array
{ {
global $database; 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; global $database;
$database->execute( $database->execute(
@ -849,7 +867,7 @@ class Artists extends Extension
/* /*
* HERE WE GET THE LIST OF ALL ARTIST WITH PAGINATION * 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; global $config, $database;
@ -927,7 +945,7 @@ class Artists extends Extension
ON a.id = aa.artist_id ON a.id = aa.artist_id
"); ");
$totalPages = ceil($count / $artistsPerPage); $totalPages = (int)ceil($count / $artistsPerPage);
$this->theme->list_artists($listing, $pageNumber + 1, $totalPages); $this->theme->list_artists($listing, $pageNumber + 1, $totalPages);
} }
@ -935,7 +953,7 @@ class Artists extends Extension
/* /*
* HERE WE ADD AN ALIAS * HERE WE ADD AN ALIAS
*/ */
private function add_urls() private function add_urls(): void
{ {
global $user; global $user;
$inputs = validate_input([ $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; global $database;
@ -962,7 +980,7 @@ class Artists extends Extension
); );
} }
private function add_alias() private function add_alias(): void
{ {
global $user; global $user;
$inputs = validate_input([ $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; global $database;
@ -989,7 +1007,7 @@ class Artists extends Extension
); );
} }
private function add_members() private function add_members(): void
{ {
global $user; global $user;
$inputs = validate_input([ $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; global $database;
@ -1040,6 +1058,8 @@ class Artists extends Extension
/** /**
* HERE WE GET THE INFO OF THE ALIAS * HERE WE GET THE INFO OF THE ALIAS
*
* @return array<string, mixed>
*/ */
private function get_alias(int $artistID): array private function get_alias(int $artistID): array
{ {

View file

@ -9,6 +9,12 @@ use MicroHTML\HTMLElement;
use function MicroHTML\emptyHTML; use function MicroHTML\emptyHTML;
use function MicroHTML\{INPUT,P}; 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 class ArtistsTheme extends Themelet
{ {
public function get_author_editor_html(string $author): HTMLElement 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; 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; global $user;
@ -137,7 +149,7 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Edit artist", $html, "main", 10)); $page->add_block(new Block("Edit artist", $html, "main", 10));
} }
public function new_artist_composer() public function new_artist_composer(): void
{ {
global $page, $user; global $page, $user;
@ -158,7 +170,10 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Artists", $html, "main", 10)); $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; global $user, $page;
@ -237,7 +252,7 @@ class ArtistsTheme extends Themelet
$this->display_paginator($page, "artist/list", null, $pageNumber, $totalPages); $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; global $user;
@ -256,7 +271,7 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Artist Aliases", $html, "main", 20)); $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; global $user;
@ -275,7 +290,7 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Artist members", $html, "main", 30)); $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; global $user;
@ -294,7 +309,10 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Artist URLs", $html, "main", 40)); $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; global $user;
@ -312,7 +330,10 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Edit Alias", $html, "main", 10)); $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; global $user;
@ -330,7 +351,10 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Edit URL", $html, "main", 10)); $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; global $user;
@ -348,7 +372,14 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Edit Member", $html, "main", 10)); $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; global $page;
@ -416,6 +447,9 @@ class ArtistsTheme extends Themelet
$page->add_block(new Block("Artist Posts", $artist_images, "main", 20)); $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 private function render_aliases(array $aliases, bool $userIsLogged, bool $userIsAdmin): string
{ {
$html = ""; $html = "";
@ -462,6 +496,9 @@ class ArtistsTheme extends Themelet
return $html; return $html;
} }
/**
* @param ArtistMember[] $members
*/
private function render_members(array $members, bool $userIsLogged, bool $userIsAdmin): string private function render_members(array $members, bool $userIsLogged, bool $userIsAdmin): string
{ {
$html = ""; $html = "";
@ -506,6 +543,9 @@ class ArtistsTheme extends Themelet
return $html; return $html;
} }
/**
* @param ArtistUrl[] $urls
*/
private function render_urls(array $urls, bool $userIsLogged, bool $userIsAdmin): string private function render_urls(array $urls, bool $userIsLogged, bool $userIsAdmin): string
{ {
$html = ""; $html = "";

View file

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

View file

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Shimmie2; namespace Shimmie2;
use MicroHTML\HTMLElement;
class AutoTaggerTheme extends Themelet class AutoTaggerTheme extends Themelet
{ {
/** /**
@ -11,7 +13,7 @@ class AutoTaggerTheme extends Themelet
* *
* Note: $can_manage = whether things like "add new alias" should be shown * 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; 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 private function complete(string $search, int $limit): array
{ {
global $cache, $database; global $cache, $database;

View file

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

View file

@ -6,7 +6,7 @@ namespace Shimmie2;
class BanWordsTest extends ShimmiePHPUnitTestCase class BanWordsTest extends ShimmiePHPUnitTestCase
{ {
public function check_blocked($image_id, $words) public function check_blocked(int $image_id, string $words): void
{ {
global $user; global $user;
try { 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(); $bb = new BBCode();
return $bb->_format($in); return $bb->_format($in);
} }
private function strip($in): string private function strip(string $in): string
{ {
$bb = new BBCode(); $bb = new BBCode();
return $bb->strip($in); return $bb->strip($in);

View file

@ -16,7 +16,10 @@ use function MicroHTML\OPTION;
class BlocksTheme extends Themelet 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; global $page;

View file

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

View file

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

View file

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

View file

@ -6,6 +6,9 @@ namespace Shimmie2;
class BulkActionsTheme extends Themelet 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 public function display_selector(Page $page, array $actions, string $query): void
{ {
$body = "<input type='hidden' name='bulk_selected_ids' id='bulk_selected_ids' /> $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. * 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; global $database;
$database->with_savepoint(function () use ($tmpname, $filename, $tags, $source, $rating, $thumbfile) { $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)) { if (!file_exists($csvfile)) {
$this->theme->add_status("Error", "$csvfile not found"); $this->theme->add_status("Error", "$csvfile not found");

View file

@ -6,6 +6,7 @@ namespace Shimmie2;
class BulkAddCSVTheme extends Themelet class BulkAddCSVTheme extends Themelet
{ {
/** @var Block[] */
private array $messages = []; private array $messages = [];
/* /*
@ -44,7 +45,7 @@ class BulkAddCSVTheme extends Themelet
$page->add_block(new Block("Bulk Add CSV", $html)); $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); $this->messages[] = new Block($title, $body);
} }

View file

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

View file

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

View file

@ -63,7 +63,10 @@ class Comment
#[Field] #[Field]
public string $posted; public string $posted;
public function __construct($row) /**
* @param array<string,mixed> $row
*/
public function __construct(array $row)
{ {
$this->owner = null; $this->owner = null;
$this->owner_id = (int)$row['user_id']; $this->owner_id = (int)$row['user_id'];
@ -96,6 +99,9 @@ class Comment
return $this->owner; return $this->owner;
} }
/**
* @return Comment[]
*/
#[Field(extends: "Post", name: "comments", type: "[Comment!]!")] #[Field(extends: "Post", name: "comments", type: "[Comment!]!")]
public static function get_comments(Image $post): array public static function get_comments(Image $post): array
{ {
@ -223,7 +229,7 @@ class CommentList extends Extension
$event->add_disallow("comment"); $event->add_disallow("comment");
} }
private function onPageRequest_add() private function onPageRequest_add(): void
{ {
global $user, $page; global $user, $page;
if (isset($_POST['image_id']) && isset($_POST['comment'])) { 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; global $user, $page;
if ($user->can(Permissions::DELETE_COMMENT)) { 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; global $user, $database, $page;
if ($user->can(Permissions::DELETE_COMMENT) && !empty($_POST["ip"])) { 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; 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)); $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); $search = $event->get_arg(1);
$page_num = $event->try_page_num(2); $page_num = $event->try_page_num(2);
@ -448,6 +454,7 @@ class CommentList extends Extension
} }
/** /**
* @param array<string,mixed> $args
* @return Comment[] * @return Comment[]
*/ */
private static function get_generic_comments(string $query, array $args): array private static function get_generic_comments(string $query, array $args): array
@ -603,7 +610,7 @@ class CommentList extends Extension
} }
// do some checks // 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; global $database, $page;
@ -628,7 +635,7 @@ class CommentList extends Extension
log_info("comment", "Comment #$cid added to >>$image_id: $snippet"); 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; global $config, $page;

View file

@ -8,10 +8,13 @@ class CommentListTheme extends Themelet
{ {
private bool $show_anon_id = false; private bool $show_anon_id = false;
private int $anon_id = 1; private int $anon_id = 1;
/** @var array<string,int> */
private array $anon_map = []; private array $anon_map = [];
/** /**
* Display a page with a list of images, and for each image, the image's comments. * 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 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")); $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 public function display_all_user_comments(array $comments, int $page_number, int $total_pages, User $user): void
{ {
global $page; 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; global $page;
if (empty($folder)) { 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; global $page, $user_config;
$path = join_path($user_config->get_string(CronUploaderConfig::DIR), $folder); $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; global $user_config;
@ -454,6 +454,8 @@ class CronUploader extends Extension
/** /**
* Generate the necessary DataUploadEvent for a given image and tags. * Generate the necessary DataUploadEvent for a given image and tags.
*
* @param string[] $tags
*/ */
private function add_image(string $tmpname, string $filename, array $tags): DataUploadEvent 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 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( public function display_documentation(
bool $running, bool $running,
array $queue_dirinfo, array $queue_dirinfo,
@ -25,7 +31,7 @@ class CronUploaderTheme extends Themelet
string $cron_cmd, string $cron_cmd,
string $cron_url, string $cron_url,
?array $log_entries ?array $log_entries
) { ): void {
global $page, $config, $user_config; global $page, $config, $user_config;
$info_html = ""; $info_html = "";
@ -159,6 +165,9 @@ class CronUploaderTheme extends Themelet
return (string)$html; return (string)$html;
} }
/**
* @param string[] $failed_dirs
*/
public function display_form(array $failed_dirs): void public function display_form(array $failed_dirs): void
{ {
global $page; global $page;

View file

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

View file

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

View file

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

View file

@ -13,10 +13,8 @@ class ETTheme extends Themelet
{ {
/* /*
* Create a page showing info * 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; global $page;
@ -26,7 +24,7 @@ class ETTheme extends Themelet
$page->add_block(new Block("Information:", $this->build_data_form($yaml))); $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( return FORM(
["action" => "https://shimmie.shishnet.org/register.php", "method" => "POST"], ["action" => "https://shimmie.shishnet.org/register.php", "method" => "POST"],

View file

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

View file

@ -206,6 +206,9 @@ class Forum extends Extension
return (int)ceil($result["count"] / $config->get_int("forumPostsPerPage")); return (int)ceil($result["count"] / $config->get_int("forumPostsPerPage"));
} }
/**
* @return string[]
*/
private function sanity_check_new_thread(): array private function sanity_check_new_thread(): array
{ {
$errors = []; $errors = [];
@ -226,6 +229,9 @@ class Forum extends Extension
return $errors; return $errors;
} }
/**
* @return string[]
*/
private function sanity_check_new_post(): array private function sanity_check_new_post(): array
{ {
$errors = []; $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}; 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 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) { if (count($threads) == 0) {
$html = "There are no threads to show."; $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; global $config, $user;
$max_characters = $config->get_int('forumMaxCharsPerPost'); $max_characters = $config->get_int('forumMaxCharsPerPost');
@ -73,9 +80,7 @@ class ForumTheme extends Themelet
$page->add_block(new Block($blockTitle, $html, "main", 120)); $page->add_block(new Block($blockTitle, $html, "main", 120));
} }
public function display_new_post_composer(Page $page, int $threadID): void
public function display_new_post_composer(Page $page, $threadID): void
{ {
global $config; 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*/; global $config, $page/*, $user*/;
@ -189,13 +196,16 @@ class ForumTheme extends Themelet
$page->add_block(new Block($threadTitle, $html, "main", 20)); $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."); $html = A(["href" => make_link("forum/nuke/".$threadID)], "Delete this thread and its posts.");
$page->add_block(new Block("Admin Actions", $html, "main", 140)); $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; 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; $n = 0;
foreach ($blocks as $block) { 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 private static function handle_uploads(): array
{ {
global $user; global $user;
@ -135,7 +138,7 @@ class GraphQL extends Extension
break; break;
} }
try { try {
$results[] = self::handle_upload($n, $common_tags, $common_source); $results[] = ["image_ids" => self::handle_upload($n, $common_tags, $common_source)];
} catch(\Exception $e) { } catch(\Exception $e) {
$results[] = ["error" => $e->getMessage()]; $results[] = ["error" => $e->getMessage()];
} }
@ -143,10 +146,14 @@ class GraphQL extends Extension
return ["results" => $results]; return ["results" => $results];
} }
/**
* @return int[]
*/
private static function handle_upload(int $n, string $common_tags, string $common_source): array private static function handle_upload(int $n, string $common_tags, string $common_source): array
{ {
global $database;
if (!empty($_POST["url$n"])) { if (!empty($_POST["url$n"])) {
throw new \Exception("URLs not handled yet"); throw new UploadException("URLs not handled yet");
} else { } else {
$ec = $_FILES["data$n"]["error"]; $ec = $_FILES["data$n"]["error"];
switch($ec) { switch($ec) {
@ -155,9 +162,9 @@ class GraphQL extends Extension
$filename = $_FILES["data$n"]["name"]; $filename = $_FILES["data$n"]["name"];
break; break;
case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_INI_SIZE:
return ["error" => "File larger than PHP can handle"]; throw new UploadException("File larger than PHP can handle");
default: 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"])) { if (!empty($_POST["source$n"])) {
$source = $_POST["source$n"]; $source = $_POST["source$n"];
} }
$event = send_event(new DataUploadEvent($tmpname, [ $event = $database->with_savepoint(function () use ($tmpname, $filename, $tags, $source) {
'filename' => $filename, return send_event(new DataUploadEvent($tmpname, [
'tags' => Tag::explode($tags), 'filename' => $filename,
'source' => $source, '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 public function onCliGen(CliGenEvent $event): void

View file

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

View file

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

View file

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

View file

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

View file

@ -4,25 +4,27 @@ declare(strict_types=1);
namespace Shimmie2; namespace Shimmie2;
use function MicroHTML\INPUT; use MicroHTML\HTMLElement;
use function MicroHTML\{INPUT,emptyHTML};
class ImageBanTheme extends Themelet class ImageBanTheme extends Themelet
{ {
/* /*
* Show all the bans * 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_title("Post Bans");
$page->set_heading("Post Bans"); $page->set_heading("Post Bans");
$page->add_block(new NavBlock()); $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 * 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( return SHM_SIMPLE_FORM(
"image_hash_ban/add", "image_hash_ban/add",

View file

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

View file

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

View file

@ -13,9 +13,13 @@ class IndexTheme extends Themelet
{ {
protected int $page_number; protected int $page_number;
protected int $total_pages; protected int $total_pages;
/** @var string[] */
protected array $search_terms; 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->page_number = $page_number;
$this->total_pages = $total_pages; $this->total_pages = $total_pages;
@ -109,7 +113,7 @@ and of course start organising your images :-)
return $table; return $table;
} }
protected function display_shortwiki(Page $page) protected function display_shortwiki(Page $page): void
{ {
global $config; global $config;
@ -141,7 +145,7 @@ and of course start organising your images :-)
/** /**
* @param Image[] $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; global $config;
@ -167,7 +171,7 @@ and of course start organising your images :-)
/** /**
* @param Image[] $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 (count($this->search_terms) > 0) {
if ($this->page_number > 3) { 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 // Check if our current IP is in either of the ban lists
$active_ban_id = ( $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 // 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; $active_ban_id = null;
if (isset($ips[$remote])) { if (isset($ips[$remote])) {
$active_ban_id = $ips[$remote]; $active_ban_id = $ips[$remote];

View file

@ -4,9 +4,13 @@ declare(strict_types=1);
namespace Shimmie2; namespace Shimmie2;
use MicroHTML\HTMLElement;
use function MicroHTML\emptyHTML;
class IPBanTheme extends Themelet 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 = " $html = "
<a href='".make_link("ip_ban/list", "r__size=1000000")."'>Show All Active</a> / <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)'); $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 private function data(Image $image): array
{ {
global $config; global $config;
@ -38,6 +41,7 @@ class LinkImage extends Extension
'thumb_src' => make_http($image->get_thumb_link()), 'thumb_src' => make_http($image->get_thumb_link()),
'image_src' => make_http($image->get_image_link()), 'image_src' => make_http($image->get_image_link()),
'post_link' => make_http(make_link("post/view/{$image->id}")), '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 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']; $thumb_src = $data['thumb_src'];
$image_src = $data['image_src']; $image_src = $data['image_src'];
$post_link = $data['post_link']; $post_link = $data['post_link'];
$text_link = $data['text_link']; $text_link = $data['text_link'];
$page->add_block(new Block( $page->add_block(new Block(
"Link to Post", "Link to Post",
" "
@ -93,7 +95,7 @@ class LinkImageTheme extends Themelet
return $text; 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 " return "
<tr> <tr>

View file

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

View file

@ -48,7 +48,7 @@ class LiveFeed extends Extension
return 99; return 99;
} }
private function msg(string $data) private function msg(string $data): void
{ {
global $config; 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; global $config, $user;
// TODO: colour based on event->priority // TODO: colour based on event->priority

View file

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

View file

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

View file

@ -31,7 +31,7 @@ class LogNet extends Extension
} }
} }
private function msg($data) private function msg(string $data): void
{ {
global $config; global $config;
$host = $config->get_string("log_net_host"); $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. * The factor of 2.5 is simply a rough guideline.
* https://stackoverflow.com/questions/527532/reasonable-php-memory-limit-for-image-resize * 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. * @return int The number of bytes an image resize operation is estimated to use.
*/ */
public static function calc_memory_use(array $info): int public static function calc_memory_use(array $info): int
@ -368,8 +368,10 @@ class Media extends Extension
return $ok; 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; global $config;
@ -410,7 +412,7 @@ class Media extends Extension
return $ext; 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) { // switch ($format) {
// case FileExtension::PNG: // case FileExtension::PNG:
@ -638,7 +640,7 @@ class Media extends Extension
* Performs a resize operation on an image file using GD. * Performs a resize operation on an image file using GD.
* *
* @param string $image_filename The source file to be resized. * @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_width
* @param int $new_height * @param int $new_height
* @param string $output_filename * @param string $output_filename
@ -658,7 +660,7 @@ class Media extends Extension
string $resize_type = self::RESIZE_TYPE_FIT, string $resize_type = self::RESIZE_TYPE_FIT,
int $output_quality = 80, int $output_quality = 80,
bool $allow_upscale = true bool $allow_upscale = true
) { ): void {
$width = $info[0]; $width = $info[0];
$height = $info[1]; $height = $info[1];
@ -785,9 +787,6 @@ class Media extends Extension
} }
$background_color = Media::hex_color_allocate($new_image, $alpha_color); $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) { if (imagefilledrectangle($new_image, 0, 0, $width, $height, $background_color) === false) {
throw new ImageTranscodeException("Could not fill background color"); 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. * Determines the dimensions of a video file using ffmpeg.
* *
* @param string $filename * @param string $filename
* @return array [width, height] * @return array{0: int, 1: int}
*/ */
public static function video_size(string $filename): array 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, '#'); $hex = ltrim($hex, '#');
$a = hexdec(substr($hex, 0, 2)); $a = hexdec(substr($hex, 0, 2));
$b = hexdec(substr($hex, 2, 2)); $b = hexdec(substr($hex, 2, 2));
$c = hexdec(substr($hex, 4, 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. * Returns all the file extension associated with the specified mimetype.
*
* @return string[]
*/ */
public static function get_all_for_mime(string $mime): array 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 public static function get_for_extension(string $ext): ?array
{ {
$ext = strtolower($ext); $ext = strtolower($ext);
@ -247,6 +250,9 @@ class MimeMap
return null; return null;
} }
/**
* @return array{name: string, ext: string[], mime: string[]}
*/
public static function get_for_mime(string $mime): ?array public static function get_for_mime(string $mime): ?array
{ {
$mime = strtolower(MimeType::remove_parameters($mime)); $mime = strtolower(MimeType::remove_parameters($mime));

View file

@ -100,6 +100,9 @@ class MimeType
return $mime; return $mime;
} }
/**
* @param array<string> $mime_array
*/
public static function matches_array(string $mime, array $mime_array, bool $exact = false): bool 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 // 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 private static function compare_file_bytes(string $file_name, array $comparison): bool
{ {
$size = filesize($file_name); $size = filesize($file_name);

View file

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

View file

@ -4,13 +4,17 @@ declare(strict_types=1);
namespace Shimmie2; namespace Shimmie2;
use MicroHTML\HTMLElement;
use function MicroHTML\emptyHTML;
class NotATagTheme extends Themelet 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_title("UnTags");
$page->set_heading("UnTags"); $page->set_heading("UnTags");
$page->add_block(new NavBlock()); $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. * HERE WE GET ALL NOTES FOR DISPLAYED IMAGE.
*
* @return array<string, mixed>
*/ */
private function get_notes(int $imageID): array private function get_notes(int $imageID): array
{ {
@ -293,7 +295,7 @@ class Notes extends Extension
return $noteID; return $noteID;
} }
private function add_note_request() private function add_note_request(): void
{ {
global $database, $user; global $database, $user;
@ -312,7 +314,7 @@ class Notes extends Extension
log_info("notes", "Note requested {$resultID} by {$user->name}"); log_info("notes", "Note requested {$resultID} by {$user->name}");
} }
private function update_note() private function update_note(): void
{ {
global $database; 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']); $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; global $user, $database;
@ -344,7 +346,7 @@ class Notes extends Extension
log_info("notes", "Note deleted {$note["note_id"]} by {$user->name}"); log_info("notes", "Note deleted {$note["note_id"]} by {$user->name}");
} }
private function nuke_notes() private function nuke_notes(): void
{ {
global $database, $user; global $database, $user;
$image_id = int_escape($_POST["image_id"]); $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}"); log_info("notes", "Notes deleted from {$image_id} by {$user->name}");
} }
private function nuke_requests() private function nuke_requests(): void
{ {
global $database, $user; global $database, $user;
$image_id = int_escape($_POST["image_id"]); $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}"); 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; global $database, $config;
@ -380,7 +382,7 @@ class Notes extends Extension
['enable' => 1, 'offset' => $pageNumber * $notesPerPage, 'limit' => $notesPerPage] ['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 = []; $images = [];
while ($row = $result->fetch()) { while ($row = $result->fetch()) {
@ -390,7 +392,7 @@ class Notes extends Extension
$this->theme->display_note_list($images, $pageNumber + 1, $totalPages); $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; global $config, $database;
@ -398,10 +400,8 @@ class Notes extends Extension
$requestsPerPage = $config->get_int('notesRequestsPerPage'); $requestsPerPage = $config->get_int('notesRequestsPerPage');
//$result = $database->get_all("SELECT * FROM pool_images WHERE pool_id=:pool_id", ['pool_id'=>$poolID]); //$result = $database->get_all("SELECT * FROM pool_images WHERE pool_id=:pool_id", ['pool_id'=>$poolID]);
$result = $database->execute( $result = $database->execute(
" "
SELECT DISTINCT image_id SELECT DISTINCT image_id
@ -410,7 +410,7 @@ class Notes extends Extension
["offset" => $pageNumber * $requestsPerPage, "limit" => $requestsPerPage] ["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 = []; $images = [];
while ($row = $result->fetch()) { while ($row = $result->fetch()) {
@ -420,7 +420,7 @@ class Notes extends Extension
$this->theme->display_note_requests($images, $pageNumber + 1, $totalPages); $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; 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; global $config, $database;
@ -455,12 +455,12 @@ class Notes extends Extension
['offset' => $pageNumber * $historiesPerPage, 'limit' => $historiesPerPage] ['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); $this->theme->display_histories($histories, $pageNumber + 1, $totalPages);
} }
private function get_history(PageRequestEvent $event) private function get_history(PageRequestEvent $event): void
{ {
global $config, $database; global $config, $database;
@ -479,7 +479,7 @@ class Notes extends Extension
['note_id' => $noteID, 'offset' => $pageNumber * $historiesPerPage, 'limit' => $historiesPerPage] ['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); $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. * 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; global $database;

View file

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

View file

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

View file

@ -6,7 +6,7 @@ namespace Shimmie2;
class NumericScoreTheme extends Themelet class NumericScoreTheme extends Themelet
{ {
public function get_voter(Image $image) public function get_voter(Image $image): void
{ {
global $user, $page; global $user, $page;
$i_image_id = $image->id; $i_image_id = $image->id;
@ -55,7 +55,7 @@ class NumericScoreTheme extends Themelet
$page->add_block(new Block("Post Score", $html, "left", 20)); $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; global $user, $page;
$html = " $html = "
@ -68,7 +68,11 @@ class NumericScoreTheme extends Themelet
$page->add_block(new Block("Votes", $html, "main", 80)); $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; global $page, $config;

View file

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

View file

@ -70,6 +70,9 @@ class PM
$this->is_read = $is_read; $this->is_read = $is_read;
} }
/**
* @param array<string, mixed> $row
*/
public static function from_row(array $row): PM public static function from_row(array $row): PM
{ {
$pm = new PM( $pm = new PM(
@ -85,6 +88,9 @@ class PM
return $pm; return $pm;
} }
/**
* @return PM[]|null
*/
#[Field(extends: "User", name: "private_messages", type: "[PrivateMessage!]")] #[Field(extends: "User", name: "private_messages", type: "[PrivateMessage!]")]
public static function get_pms(User $duser): ?array 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}"); 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; global $database;

View file

@ -6,7 +6,10 @@ namespace Shimmie2;
class PrivMsgTheme extends Themelet 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; global $user;
@ -58,7 +61,7 @@ class PrivMsgTheme extends Themelet
$page->add_block(new Block("Private Messages", $html, "main", 40, "private-messages")); $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; global $user;
$post_url = make_link("pm/send"); $post_url = make_link("pm/send");

View file

@ -26,8 +26,12 @@ class PoolCreationException extends SCoreException
class PoolAddPostsEvent extends Event class PoolAddPostsEvent extends Event
{ {
public int $pool_id; public int $pool_id;
/** @var int[] */
public array $posts = []; public array $posts = [];
/**
* @param int[] $posts
*/
public function __construct(int $pool_id, array $posts) public function __construct(int $pool_id, array $posts)
{ {
parent::__construct(); parent::__construct();
@ -82,6 +86,9 @@ class Pool
public string $date; public string $date;
public int $posts; public int $posts;
/**
* @param array<string,mixed> $row
*/
public function __construct(array $row) public function __construct(array $row)
{ {
$this->id = (int)$row['id']; $this->id = (int)$row['id'];
@ -94,12 +101,15 @@ class Pool
$this->posts = (int)$row['posts']; $this->posts = (int)$row['posts'];
} }
/**
* @param array<string,mixed> $row
*/
public static function makePool(array $row): Pool public static function makePool(array $row): Pool
{ {
return new Pool($row); 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; global $database;
$row = $database->get_row("SELECT * FROM pools WHERE title=:title", ["title" => $poolTitle]); $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; 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. * 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; global $database;
if (empty($imageID)) {
return null;
}
return $database->get_row( return $database->get_row(
" "
SELECT ( SELECT (
SELECT image_id SELECT image_id
FROM pool_images FROM pool_images
WHERE pool_id = :pid WHERE pool_id = :pid
AND image_order < ( AND image_order < (
SELECT image_order SELECT image_order
FROM pool_images FROM pool_images
WHERE pool_id = :pid WHERE pool_id = :pid
AND image_id = :iid AND image_id = :iid
LIMIT 1 LIMIT 1
) )
ORDER BY image_order DESC LIMIT 1 ORDER BY image_order DESC LIMIT 1
) AS prev, ) AS prev,
( (
SELECT image_id SELECT image_id
FROM pool_images FROM pool_images
WHERE pool_id = :pid WHERE pool_id = :pid
AND image_order > ( AND image_order > (
SELECT image_order SELECT image_order
FROM pool_images FROM pool_images
WHERE pool_id = :pid WHERE pool_id = :pid
AND image_id = :iid AND image_id = :iid
LIMIT 1 LIMIT 1
) )
ORDER BY image_order ASC LIMIT 1 ORDER BY image_order ASC LIMIT 1
) AS next ) AS next
LIMIT 1", LIMIT 1
",
["pid" => $pool->id, "iid" => $imageID] ["pid" => $pool->id, "iid" => $imageID]
); );
} }
@ -814,7 +821,7 @@ class Pools extends Extension
/** /**
* Retrieve all the images in a pool, given a pool ID. * 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; global $config, $user, $database;
@ -885,7 +892,7 @@ class Pools extends Extension
* *
* $action Action=1 (one) MEANS ADDED, Action=0 (zero) MEANS REMOVED * $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; 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; global $config, $database;
@ -923,7 +930,7 @@ class Pools extends Extension
/** /**
* HERE GO BACK IN HISTORY AND ADD OR REMOVE POSTS TO POOL. * 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; global $database;
$status = $database->get_all("SELECT * FROM pool_history WHERE id=:hid", ["hid" => $historyID]); $status = $database->get_all("SELECT * FROM pool_history WHERE id=:hid", ["hid" => $historyID]);
@ -1009,7 +1016,7 @@ class Pools extends Extension
return true; return true;
} }
private function update_count(int $pool_id) private function update_count(int $pool_id): void
{ {
global $database; global $database;
$database->execute( $database->execute(

View file

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

View file

@ -10,13 +10,18 @@ use function MicroHTML\emptyHTML;
use function MicroHTML\rawHTML; use function MicroHTML\rawHTML;
use function MicroHTML\{A,BR,DIV,INPUT,P,SCRIPT,SPAN,TABLE,TBODY,TD,TEXTAREA,TH,THEAD,TR}; 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 class PoolsTheme extends Themelet
{ {
/** /**
* Adds a block to the panel with information on the pool(s) the image is in. * 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. * $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; global $page;
@ -25,13 +30,11 @@ class PoolsTheme extends Themelet
foreach ($navIDs as $poolID => $poolInfo) { foreach ($navIDs as $poolID => $poolInfo) {
$div = DIV(SHM_A("pool/view/" . $poolID, $poolInfo["info"]->title)); $div = DIV(SHM_A("pool/view/" . $poolID, $poolInfo["info"]->title));
if (!empty($poolInfo["nav"])) { if (!empty($poolInfo["nav"]["prev"])) {
if (!empty($poolInfo["nav"]["prev"])) { $div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["prev"], "Prev", class: "pools_prev_img"));
$div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["prev"], "Prev", class: "pools_prev_img")); }
} if (!empty($poolInfo["nav"]["next"])) {
if (!empty($poolInfo["nav"]["next"])) { $div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["next"], "Next", class: "pools_next_img"));
$div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["next"], "Next", class: "pools_next_img"));
}
} }
$linksPools->appendChild($div); $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 public function get_adder_html(Image $image, array $pools): HTMLElement
{ {
return SHM_SIMPLE_FORM( return SHM_SIMPLE_FORM(
@ -54,8 +60,10 @@ class PoolsTheme extends Themelet
/** /**
* HERE WE SHOWS THE LIST OF POOLS. * 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. // Build up the list of pools.
$pool_rows = []; $pool_rows = [];
@ -95,7 +103,7 @@ class PoolsTheme extends Themelet
/* /*
* HERE WE DISPLAY THE NEW POOL COMPOSER * 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( $form = SHM_SIMPLE_FORM("pool/create", TABLE(
TR(TD("Title:"), TD(INPUT(["type" => "text", "name" => "title"]))), 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)); $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; global $page, $user;
@ -146,8 +154,10 @@ class PoolsTheme extends Themelet
/** /**
* HERE WE DISPLAY THE POOL WITH TITLE DESCRIPTION AND IMAGES WITH PAGINATION. * 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; 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. * 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; global $user;
@ -246,8 +256,10 @@ class PoolsTheme extends Themelet
/** /**
* HERE WE DISPLAY THE RESULT OF THE SEARCH ON IMPORT. * 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); $this->display_top($pool, "Importing Posts", true);
@ -283,8 +295,10 @@ class PoolsTheme extends Themelet
/** /**
* HERE WE DISPLAY THE POOL ORDERER. * 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 * 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"); $this->display_top($pool, "Sorting Pool");
@ -293,7 +307,7 @@ class PoolsTheme extends Themelet
$form->appendChild(SPAN( $form->appendChild(SPAN(
["class" => "thumb"], ["class" => "thumb"],
$this->build_thumb_html($image), $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]) 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 * WE LIST ALL IMAGES ON POOL WITHOUT PAGINATION AND WITH
* A CHECKBOX TO SELECT WHICH IMAGE WE WANT TO REMOVE * 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]); $_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. * 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; global $page;
@ -397,11 +415,17 @@ class PoolsTheme extends Themelet
$this->display_paginator($page, "pool/updated", null, $pageNumber, $totalPages); $this->display_paginator($page, "pool/updated", null, $pageNumber, $totalPages);
} }
/**
* @param array<int,string> $options
*/
public function get_bulk_pool_selector(array $options): HTMLElement public function get_bulk_pool_selector(array $options): HTMLElement
{ {
return SHM_SELECT("bulk_pool_select", $options, required: true, empty_option: true); 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 public function get_bulk_pool_input(array $search_terms): HTMLElement
{ {
return INPUT( return INPUT(
@ -410,7 +434,7 @@ class PoolsTheme extends Themelet
"name" => "bulk_pool_new", "name" => "bulk_pool_new",
"placeholder" => "New Pool", "placeholder" => "New Pool",
"required" => "", "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 $key = self::KEY;
public string $name = "Post Peek"; public string $name = "Post Peek";
public string $url = self::SHIMMIE_URL; 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 $license = self::LICENSE_WTFPL;
public string $description = "Peek at posts"; 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; global $database;
$database->execute("UPDATE images SET title=:title WHERE id=:id", ['title' => $title, 'id' => $image_id]); $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 private function no_private_query(array $context): bool
{ {
foreach ($context as $term) { foreach ($context as $term) {
@ -201,7 +203,7 @@ class PrivateImage extends Extension
return true; return true;
} }
public static function privatize_image($image_id) public static function privatize_image(int $image_id): void
{ {
global $database; 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; global $database;

View file

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

View file

@ -6,12 +6,13 @@ namespace Shimmie2;
class RandomListTheme extends Themelet class RandomListTheme extends Themelet
{ {
/** @var string[] */
protected array $search_terms; protected array $search_terms;
/** /**
* @param string[] $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; $this->search_terms = $search_terms;
} }
@ -42,6 +43,9 @@ class RandomListTheme extends Themelet
$page->add_block(new Block("Navigation", $nav, "left", 0)); $page->add_block(new Block("Navigation", $nav, "left", 0));
} }
/**
* @param string[] $search_terms
*/
protected function build_navigation(array $search_terms): string protected function build_navigation(array $search_terms): string
{ {
$h_search_string = html_escape(Tag::implode($search_terms)); $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 public static function get_sorted_ratings(): array
{ {
global $_shm_ratings; global $_shm_ratings;
@ -421,6 +424,10 @@ class Ratings extends Extension
return $ratings; return $ratings;
} }
/**
* @param ImageRating[]|null $ratings
* @return array<string, string>
*/
public static function get_ratings_dict(array $ratings = null): array public static function get_ratings_dict(array $ratings = null): array
{ {
if (!isset($ratings)) { if (!isset($ratings)) {
@ -464,6 +471,9 @@ class Ratings extends Extension
return array_intersect($available, $selected); return array_intersect($available, $selected);
} }
/**
* @param string[] $privs
*/
public static function privs_to_sql(array $privs): string public static function privs_to_sql(array $privs): string
{ {
$arr = []; $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; global $database;
if ($old_rating != $rating) { if ($old_rating != $rating) {

View file

@ -11,6 +11,10 @@ use function MicroHTML\{A,P,TABLE,TD,TH,TR};
class RatingsTheme extends Themelet 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 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); 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 public function display_form(array $current_ratings): void
{ {
global $page; global $page;
@ -39,6 +46,9 @@ class RatingsTheme extends Themelet
$page->add_block(new Block("Update Ratings", SHM_SIMPLE_FORM("admin/update_ratings", $table))); $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 public function get_help_html(array $ratings): HTMLElement
{ {
$rating_rows = [TR(TH("Name"), TH("Search Term"), TH("Abbreviation"))]; $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 public static function get_children(Image $image, int $omit = null): array
{ {
global $database; global $database;
@ -183,7 +186,7 @@ class Relationships extends Extension
return $output; return $output;
} }
private function remove_parent(int $imageID) private function remove_parent(int $imageID): void
{ {
global $database; global $database;
$parentID = $database->get_one("SELECT parent_id FROM images WHERE id = :iid", ["iid" => $imageID]); $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; global $database;

View file

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