refactor: add psalm

Signed-off-by: Varun Patil <radialapps@gmail.com>
pull/877/head
Varun Patil 2023-10-14 01:25:50 -07:00
parent ba959d2c43
commit 71ef41f763
47 changed files with 315 additions and 207 deletions

View File

@ -34,6 +34,7 @@ $config
'@PhpCsFixer:risky' => true, '@PhpCsFixer:risky' => true,
'general_phpdoc_annotation_remove' => ['annotations' => ['expectedDeprecation']], // one should use PHPUnit built-in method instead 'general_phpdoc_annotation_remove' => ['annotations' => ['expectedDeprecation']], // one should use PHPUnit built-in method instead
'modernize_strpos' => false, // needs PHP 8+ or polyfill 'modernize_strpos' => false, // needs PHP 8+ or polyfill
'phpdoc_to_comment' => ['ignored_tags' => ['psalm-suppress', 'template-implements']],
]) ])
->setFinder($finder) ->setFinder($finder)
; ;

View File

@ -1,17 +1,20 @@
all: dev-setup lint build-js-production test all: dev-setup lint build-js-production test
# Dev env management # Dev env management
dev-setup: clean clean-dev npm-init exiftool php-cs-fixer dev-setup: clean clean-dev npm-init exiftool install-tools
exiftool: exiftool:
sh scripts/get-exiftool.sh sh scripts/get-exiftool.sh
php-cs-fixer: install-tools:
mkdir -p tools/php-cs-fixer mkdir -p tools
composer require --dev --working-dir=tools/php-cs-fixer friendsofphp/php-cs-fixer composer require --dev --working-dir=tools friendsofphp/php-cs-fixer vimeo/psalm
php-lint: php-lint:
tools/php-cs-fixer/vendor/bin/php-cs-fixer fix lib tools/vendor/bin/php-cs-fixer fix lib
psalm:
tools/vendor/bin/psalm
npm-init: npm-init:
npm ci npm ci
@ -19,7 +22,7 @@ npm-init:
npm-update: npm-update:
npm update npm update
.PHONY: dev-setup exiftool php-cs-fixer php-lint npm-init npm-update .PHONY: dev-setup exiftool install-tools php-lint psalm npm-init npm-update
# Building # Building
build-js: build-js:

View File

@ -1,6 +1,6 @@
{ {
"name": "Memories", "name": "radialapps/memories",
"description": "p", "description": "Fast and advanced photo management for Nextcloud",
"type": "project", "type": "project",
"license": "AGPL", "license": "AGPL",
"authors": [ "authors": [
@ -9,7 +9,5 @@
} }
], ],
"require": {}, "require": {},
"require-dev": { "require-dev": {}
"phpunit/phpunit": "^5.4"
}
} }

View File

@ -60,7 +60,7 @@ class AlbumsBackend extends Backend
return Util::albumsIsEnabled(); return Util::albumsIsEnabled();
} }
public function clusterName(string $name) public function clusterName(string $name): string
{ {
return explode('/', $name)[1]; return explode('/', $name)[1];
} }
@ -138,7 +138,7 @@ class AlbumsBackend extends Backend
return $this->albumsQuery->getAlbumPhotos($id, $limit) ?? []; return $this->albumsQuery->getAlbumPhotos($id, $limit) ?? [];
} }
public function sortPhotosForPreview(array &$photos) public function sortPhotosForPreview(array &$photos): void
{ {
// Do nothing, the photos are already sorted by added date desc // Do nothing, the photos are already sorted by added date desc
} }

View File

@ -83,7 +83,7 @@ abstract class Backend
/** /**
* Human readable name for the cluster. * Human readable name for the cluster.
*/ */
public function clusterName(string $name) public function clusterName(string $name): string
{ {
return $name; return $name;
} }
@ -92,7 +92,7 @@ abstract class Backend
* Put the photo objects in priority list. * Put the photo objects in priority list.
* Works on the array in place. * Works on the array in place.
*/ */
public function sortPhotosForPreview(array &$photos) public function sortPhotosForPreview(array &$photos): void
{ {
shuffle($photos); shuffle($photos);
} }

View File

@ -191,7 +191,7 @@ class FaceRecognitionBackend extends Backend
return $this->tq->executeQueryWithCTEs($query)->fetchAll() ?: []; return $this->tq->executeQueryWithCTEs($query)->fetchAll() ?: [];
} }
public function sortPhotosForPreview(array &$photos) public function sortPhotosForPreview(array &$photos): void
{ {
// Convert to recognize format (percentage position-size) // Convert to recognize format (percentage position-size)
foreach ($photos as &$p) { foreach ($photos as &$p) {
@ -216,15 +216,15 @@ class FaceRecognitionBackend extends Backend
private function model(): int private function model(): int
{ {
return (int) $this->config->getAppValue('facerecognition', 'model', -1); return (int) $this->config->getAppValue('facerecognition', 'model', (string) -1);
} }
private function minFaceInClusters(): int private function minFaceInClusters(): int
{ {
return (int) $this->config->getAppValue('facerecognition', 'min_faces_in_cluster', 5); return (int) $this->config->getAppValue('facerecognition', 'min_faces_in_cluster', (string) 5);
} }
private function getFaceRecognitionClusters(int $fileid = 0) private function getFaceRecognitionClusters(int $fileid = 0): array
{ {
$query = $this->tq->getBuilder(); $query = $this->tq->getBuilder();
@ -276,7 +276,7 @@ class FaceRecognitionBackend extends Backend
return $this->tq->executeQueryWithCTEs($query)->fetchAll() ?: []; return $this->tq->executeQueryWithCTEs($query)->fetchAll() ?: [];
} }
private function getFaceRecognitionPersons(int $fileid = 0) private function getFaceRecognitionPersons(int $fileid = 0): array
{ {
$query = $this->tq->getBuilder(); $query = $this->tq->getBuilder();

View File

@ -87,11 +87,13 @@ trait PeopleBackendUtils
* @param array $photo The face object * @param array $photo The face object
* @param float $padding The padding to add around the face * @param float $padding The padding to add around the face
* *
* @return [Blob, mimetype] of resulting image * @return string[] [Blob, mimetype] of resulting image
* *
* @throws \Exception if file could not be used * @throws \Exception if file could not be used
*
* @psalm-return list{string, string}
*/ */
private function cropFace($file, array $photo, float $padding) private function cropFace($file, array $photo, float $padding): array
{ {
$img = new \OCP\Image(); $img = new \OCP\Image();
$img->loadFromData($file->getContent()); $img->loadFromData($file->getContent());
@ -121,6 +123,13 @@ trait PeopleBackendUtils
// Max 512x512 // Max 512x512
$img->scaleDownToFit(512, 512); $img->scaleDownToFit(512, 512);
return [$img->data(), $img->mimeType()]; // Get blob and mimetype
$data = $img->data();
$mime = $img->mimeType();
if (null === $data || null === $mime) {
throw new \Exception('Could not get image data');
}
return [$data, $mime];
} }
} }

View File

@ -231,7 +231,7 @@ class RecognizeBackend extends Backend
return $this->tq->executeQueryWithCTEs($query)->fetchAll() ?: []; return $this->tq->executeQueryWithCTEs($query)->fetchAll() ?: [];
} }
public function sortPhotosForPreview(array &$photos) public function sortPhotosForPreview(array &$photos): void
{ {
$this->sortByScores($photos); $this->sortByScores($photos);
} }

View File

@ -203,7 +203,7 @@ class Index extends Command
* *
* @param mixed $closure * @param mixed $closure
*/ */
private function runForUsers($closure) private function runForUsers($closure): void
{ {
if ($uid = $this->opts->user) { if ($uid = $this->opts->user) {
if ($user = $this->userManager->get($uid)) { if ($user = $this->userManager->get($uid)) {

View File

@ -296,7 +296,12 @@ class MigrateGoogleTakeout extends Command
++$this->nProcessed; ++$this->nProcessed;
} }
protected function takeoutToExiftoolJson(array $json) /**
* @return (float|mixed|string)[]
*
* @psalm-return array<string, float|mixed|string>
*/
protected function takeoutToExiftoolJson(array $json): array
{ {
// Helper to get a value from nested JSON // Helper to get a value from nested JSON
$get = static function (string $source) use ($json) { $get = static function (string $source) use ($json) {

View File

@ -109,9 +109,9 @@ class AdminController extends GenericApiController
$status['indexed_count'] = $index->getIndexedCount(); $status['indexed_count'] = $index->getIndexedCount();
// Automatic indexing stats // Automatic indexing stats
$jobStart = $config->getAppValue(Application::APPNAME, 'last_index_job_start', 0); $jobStart = (int) $config->getAppValue(Application::APPNAME, 'last_index_job_start', (string) 0);
$status['last_index_job_start'] = $jobStart ? time() - $jobStart : 0; // Seconds ago $status['last_index_job_start'] = $jobStart ? time() - $jobStart : 0; // Seconds ago
$status['last_index_job_duration'] = $config->getAppValue(Application::APPNAME, 'last_index_job_duration', 0); $status['last_index_job_duration'] = (float) $config->getAppValue(Application::APPNAME, 'last_index_job_duration', (string) 0);
$status['last_index_job_status'] = $config->getAppValue(Application::APPNAME, 'last_index_job_status', 'Indexing has not been run yet'); $status['last_index_job_status'] = $config->getAppValue(Application::APPNAME, 'last_index_job_status', 'Indexing has not been run yet');
$status['last_index_job_status_type'] = $config->getAppValue(Application::APPNAME, 'last_index_job_status_type', 'warning'); $status['last_index_job_status_type'] = $config->getAppValue(Application::APPNAME, 'last_index_job_status_type', 'warning');

View File

@ -134,7 +134,7 @@ class DaysController extends GenericApiController
/** /**
* Get transformations depending on the request. * Get transformations depending on the request.
*/ */
private function getTransformations() private function getTransformations(): array
{ {
$transforms = []; $transforms = [];
@ -180,7 +180,7 @@ class DaysController extends GenericApiController
* *
* @param array $days the days array * @param array $days the days array
*/ */
private function preloadDays(array &$days) private function preloadDays(array &$days): void
{ {
// Do not preload anything for native clients. // Do not preload anything for native clients.
// Since the contents of preloads are trusted, clients will not load locals. // Since the contents of preloads are trusted, clients will not load locals.
@ -234,7 +234,7 @@ class DaysController extends GenericApiController
* Convert days response to months response. * Convert days response to months response.
* The dayId is used to group the days into months. * The dayId is used to group the days into months.
*/ */
private function daysToMonths(array $days) private function daysToMonths(array $days): array
{ {
$months = []; $months = [];
foreach ($days as $day) { foreach ($days as $day) {
@ -255,45 +255,49 @@ class DaysController extends GenericApiController
return $months; return $months;
} }
/** Convert list of month IDs to list of dayIds */ /**
private function monthIdToDayIds(int $monthId) * Convert list of month IDs to list of dayIds.
*
* @return int[] The list of dayIds
*/
private function monthIdToDayIds(int $monthId): array
{ {
$dayIds = []; $dayIds = [];
$firstDay = (int) $monthId; $firstDay = (int) $monthId;
$lastDay = strtotime(date('Ymt', $firstDay * 86400)) / 86400; $lastDay = strtotime(date('Ymt', $firstDay * 86400)) / 86400;
for ($i = $firstDay; $i <= $lastDay; ++$i) { for ($i = $firstDay; $i <= $lastDay; ++$i) {
$dayIds[] = (string) $i; $dayIds[] = $i;
} }
return $dayIds; return $dayIds;
} }
private function isRecursive() private function isRecursive(): bool
{ {
return null === $this->request->getParam('folder') || $this->request->getParam('recursive'); return null === $this->request->getParam('folder') || $this->request->getParam('recursive');
} }
private function isArchive() private function isArchive(): bool
{ {
return null !== $this->request->getParam('archive'); return null !== $this->request->getParam('archive');
} }
private function isHidden() private function isHidden(): bool
{ {
return null !== $this->request->getParam('hidden'); return null !== $this->request->getParam('hidden');
} }
private function noPreload() private function noPreload(): bool
{ {
return null !== $this->request->getParam('nopreload'); return null !== $this->request->getParam('nopreload');
} }
private function isMonthView() private function isMonthView(): bool
{ {
return null !== $this->request->getParam('monthView'); return null !== $this->request->getParam('monthView');
} }
private function isReverse() private function isReverse(): bool
{ {
return null !== $this->request->getParam('reverse'); return null !== $this->request->getParam('reverse');
} }

View File

@ -282,7 +282,7 @@ class DownloadController extends GenericApiController
/** @var bool|resource */ /** @var bool|resource */
$handle = false; $handle = false;
/** @var ?File */ /** @var ?\OCP\Files\File */
$file = null; $file = null;
/** @var ?string */ /** @var ?string */

View File

@ -50,7 +50,7 @@ class ImageController extends GenericApiController
int $y = 32, int $y = 32,
bool $a = false, bool $a = false,
string $mode = 'fill' string $mode = 'fill'
) { ): Http\Response {
return Util::guardEx(function () use ($id, $x, $y, $a, $mode) { return Util::guardEx(function () use ($id, $x, $y, $a, $mode) {
if (-1 === $id || 0 === $x || 0 === $y) { if (-1 === $id || 0 === $x || 0 === $y) {
throw Exceptions::MissingParameter('id, x, y'); throw Exceptions::MissingParameter('id, x, y');

View File

@ -77,7 +77,7 @@ class OtherController extends GenericApiController
} }
// helper function to get user config values // helper function to get user config values
$getAppConfig = function ($key, $default) use ($uid) { $getAppConfig = function ($key, $default) use ($uid): string {
return $this->config->getUserValue($uid, Application::APPNAME, $key, $default); return $this->config->getUserValue($uid, Application::APPNAME, $key, $default);
}; };

View File

@ -69,7 +69,7 @@ class PageController extends Controller
{ {
// Image domains MUST be added to the connect domain list // Image domains MUST be added to the connect domain list
// because of the service worker fetch() call // because of the service worker fetch() call
$addImageDomain = static function ($url) use (&$policy) { $addImageDomain = static function ($url) use (&$policy): void {
$policy->addAllowedImageDomain($url); $policy->addAllowedImageDomain($url);
$policy->addAllowedConnectDomain($url); $policy->addAllowedConnectDomain($url);
}; };
@ -108,7 +108,7 @@ class PageController extends Controller
/** /**
* Get params for main.php template. * Get params for main.php template.
*/ */
public static function getMainParams() public static function getMainParams(): array
{ {
return [ return [
'native' => Util::callerIsNative(), 'native' => Util::callerIsNative(),

View File

@ -139,7 +139,7 @@ class PublicAlbumController extends Controller
return $downloadController->file($handle); return $downloadController->file($handle);
} }
private function addOgMetadata(array $album, string $token) private function addOgMetadata(array $album, string $token): void
{ {
$fileId = (int) $album['last_added_photo']; $fileId = (int) $album['last_added_photo'];
$albumId = (int) $album['album_id']; $albumId = (int) $album['album_id'];

View File

@ -111,7 +111,7 @@ class ShareController extends GenericApiController
}); });
} }
private function getNodeByIdOrPath($id, $path) private function getNodeByIdOrPath($id, $path): \OCP\Files\Node
{ {
$uid = Util::getUID(); $uid = Util::getUID();
@ -133,7 +133,7 @@ class ShareController extends GenericApiController
return $file; return $file;
} }
private function makeShareResponse(\OCP\Share\IShare $share) private function makeShareResponse(\OCP\Share\IShare $share): array
{ {
/** @var \OCP\IURLGenerator $urlGenerator */ /** @var \OCP\IURLGenerator $urlGenerator */
$urlGenerator = \OC::$server->get(\OCP\IURLGenerator::class); $urlGenerator = \OC::$server->get(\OCP\IURLGenerator::class);

View File

@ -118,7 +118,7 @@ class VideoController extends GenericApiController
string $liveid = '', string $liveid = '',
string $format = '', string $format = '',
string $transcode = '' string $transcode = ''
) { ): Http\Response {
return Util::guardEx(function () use ($fileid, $liveid, $format, $transcode) { return Util::guardEx(function () use ($fileid, $liveid, $format, $transcode) {
$file = $this->fs->getUserFile($fileid); $file = $this->fs->getUserFile($fileid);
@ -230,7 +230,7 @@ class VideoController extends GenericApiController
}); });
} }
private function getUpstream(string $client, string $path, string $profile) private function getUpstream(string $client, string $path, string $profile): int
{ {
$returnCode = $this->getUpstreamInternal($client, $path, $profile); $returnCode = $this->getUpstreamInternal($client, $path, $profile);
@ -251,7 +251,7 @@ class VideoController extends GenericApiController
return $returnCode; return $returnCode;
} }
private function getUpstreamInternal(string $client, string $path, string $profile) private function getUpstreamInternal(string $client, string $path, string $profile): int
{ {
// Make sure query params are repeated // Make sure query params are repeated
// For example, in folder sharing, we need the params on every request // For example, in folder sharing, we need the params on every request

View File

@ -39,7 +39,7 @@ class IndexJob extends TimedJob
$this->setInterval(INTERVAL); $this->setInterval(INTERVAL);
} }
protected function run($arguments) protected function run($argument)
{ {
// Check if indexing is enabled // Check if indexing is enabled
if ('0' === Util::getSystemConfig('memories.index.mode')) { if ('0' === Util::getSystemConfig('memories.index.mode')) {
@ -47,12 +47,12 @@ class IndexJob extends TimedJob
} }
// Store the last run time // Store the last run time
$this->config->setAppValue(Application::APPNAME, 'last_index_job_start', time()); $this->config->setAppValue(Application::APPNAME, 'last_index_job_start', (string) time());
$this->config->setAppValue(Application::APPNAME, 'last_index_job_duration', 0); $this->config->setAppValue(Application::APPNAME, 'last_index_job_duration', (string) 0);
// Run for a maximum of 5 minutes // Run for a maximum of 5 minutes
$startTime = microtime(true); $startTime = microtime(true);
$this->service->continueCheck = static function () use ($startTime) { $this->service->continueCheck = static function () use ($startTime): bool {
return (microtime(true) - $startTime) < MAX_RUN_TIME; return (microtime(true) - $startTime) < MAX_RUN_TIME;
}; };
@ -81,7 +81,7 @@ class IndexJob extends TimedJob
// Store the last run duration // Store the last run duration
$duration = round(microtime(true) - $startTime, 2); $duration = round(microtime(true) - $startTime, 2);
$this->config->setAppValue(Application::APPNAME, 'last_index_job_duration', $duration); $this->config->setAppValue(Application::APPNAME, 'last_index_job_duration', (string) $duration);
} }
/** /**

View File

@ -10,7 +10,7 @@ class AddMissingIndices
/** /**
* Add missing indices to the database schema. * Add missing indices to the database schema.
*/ */
public static function run(IOutput $output) public static function run(IOutput $output): SchemaWrapper
{ {
$connection = \OC::$server->get(\OC\DB\Connection::class); $connection = \OC::$server->get(\OC\DB\Connection::class);
$schema = new SchemaWrapper($connection); $schema = new SchemaWrapper($connection);

View File

@ -22,7 +22,7 @@ class AlbumsQuery
* @param bool $shared Whether to get shared albums * @param bool $shared Whether to get shared albums
* @param int $fileid File to filter by * @param int $fileid File to filter by
*/ */
public function getList(string $uid, bool $shared = false, int $fileid = 0) public function getList(string $uid, bool $shared = false, int $fileid = 0): array
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -234,7 +234,7 @@ class AlbumsQuery
/** /**
* Get list of photos in album. * Get list of photos in album.
*/ */
public function getAlbumPhotos(int $albumId, ?int $limit) public function getAlbumPhotos(int $albumId, ?int $limit): array
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -283,8 +283,10 @@ class AlbumsQuery
return $groups; return $groups;
} }
/** Get the name of the collaborators table */ /**
private function collaboratorsTable() * Get the name of the collaborators table.
*/
private function collaboratorsTable(): string
{ {
// https://github.com/nextcloud/photos/commit/20e3e61ad577014e5f092a292c90a8476f630355 // https://github.com/nextcloud/photos/commit/20e3e61ad577014e5f092a292c90a8476f630355
$appManager = \OC::$server->get(\OCP\App\IAppManager::class); $appManager = \OC::$server->get(\OCP\App\IAppManager::class);

View File

@ -74,7 +74,7 @@ class FsManager
* @param TimelineRoot $root Root object to populate (by reference) * @param TimelineRoot $root Root object to populate (by reference)
* @param bool $recursive Whether to get the folders recursively * @param bool $recursive Whether to get the folders recursively
*/ */
public function populateRoot(TimelineRoot &$root, bool $recursive = true) public function populateRoot(TimelineRoot &$root, bool $recursive = true): TimelineRoot
{ {
$user = $this->userSession->getUser(); $user = $this->userSession->getUser();
@ -183,7 +183,7 @@ class FsManager
/** /**
* Get a file with ID for the current user. * Get a file with ID for the current user.
* *
* @throws Exceptions\NotFoundFile * @throws \OCA\Memories\HttpResponseException
*/ */
public function getUserFile(int $fileId): File public function getUserFile(int $fileId): File
{ {
@ -298,7 +298,7 @@ class FsManager
return null; return null;
} }
public function getShareObject() public function getShareObject(): ?IShare
{ {
// Get token from request // Get token from request
$token = $this->getShareToken(); $token = $this->getShareToken();

View File

@ -18,8 +18,10 @@ class LivePhoto
$this->connection = $connection; $this->connection = $connection;
} }
/** Check if a given Exif data is the video part of a Live Photo */ /**
public function isVideoPart(array $exif) * Check if a given Exif data is the video part of a Live Photo.
*/
public function isVideoPart(array $exif): bool
{ {
return \array_key_exists('MIMEType', $exif) return \array_key_exists('MIMEType', $exif)
&& 'video/quicktime' === $exif['MIMEType'] && 'video/quicktime' === $exif['MIMEType']

View File

@ -37,16 +37,19 @@ class TimelineQuery
$this->request = $request; $this->request = $request;
} }
public function allowEmptyRoot(bool $value = true) public function allowEmptyRoot(bool $value = true): void
{ {
$this->_rootEmptyAllowed = $value; $this->_rootEmptyAllowed = $value;
} }
public function getBuilder() public function getBuilder(): IQueryBuilder
{ {
return $this->connection->getQueryBuilder(); return $this->connection->getQueryBuilder();
} }
/**
* @return never
*/
public static function debugQuery(IQueryBuilder &$query, string $sql = '') public static function debugQuery(IQueryBuilder &$query, string $sql = '')
{ {
// Print the query and exit // Print the query and exit
@ -58,7 +61,7 @@ class TimelineQuery
exit; // only for debugging, so this is okay exit; // only for debugging, so this is okay
} }
public static function replaceQueryParams(IQueryBuilder &$query, string $sql) public static function replaceQueryParams(IQueryBuilder &$query, string $sql): string
{ {
$params = $query->getParameters(); $params = $query->getParameters();
$platform = $query->getConnection()->getDatabasePlatform(); $platform = $query->getConnection()->getDatabasePlatform();

View File

@ -57,11 +57,11 @@ trait TimelineQueryDays
/** /**
* Get the day response from the database for the timeline. * Get the day response from the database for the timeline.
* *
* @param int[] $day_ids The day ids to fetch * @param ?int[] $day_ids The day ids to fetch
* @param bool $recursive If the query should be recursive * @param bool $recursive If the query should be recursive
* @param bool $archive If the query should include only the archive folder * @param bool $archive If the query should include only the archive folder
* @param bool $hidden If the query should include hidden files * @param bool $hidden If the query should include hidden files
* @param array $queryTransforms The query transformations to apply * @param array $queryTransforms The query transformations to apply
* *
* @return array An array of day responses * @return array An array of day responses
*/ */
@ -124,7 +124,7 @@ trait TimelineQueryDays
return $day; return $day;
} }
public function executeQueryWithCTEs(IQueryBuilder $query, string $psql = '') public function executeQueryWithCTEs(IQueryBuilder $query, string $psql = ''): \OCP\DB\IResult
{ {
$sql = empty($psql) ? $query->getSQL() : $psql; $sql = empty($psql) ? $query->getSQL() : $psql;
$params = $query->getParameters(); $params = $query->getParameters();
@ -211,7 +211,7 @@ trait TimelineQueryDays
* *
* @param array $days * @param array $days
*/ */
private function processDays($days) private function processDays($days): array
{ {
foreach ($days as &$row) { foreach ($days as &$row) {
$row['dayid'] = (int) $row['dayid']; $row['dayid'] = (int) $row['dayid'];
@ -224,7 +224,7 @@ trait TimelineQueryDays
/** /**
* Process the single day response. * Process the single day response.
*/ */
private function processDayPhoto(array &$row) private function processDayPhoto(array &$row): void
{ {
// Convert field types // Convert field types
$row['fileid'] = (int) $row['fileid']; $row['fileid'] = (int) $row['fileid'];
@ -278,7 +278,7 @@ trait TimelineQueryDays
TimelineRoot &$root, TimelineRoot &$root,
bool $archive, bool $archive,
bool $hidden bool $hidden
) { ): void {
// Add query parameters // Add query parameters
$query->setParameter('topFolderIds', $root->getIds(), IQueryBuilder::PARAM_INT_ARRAY); $query->setParameter('topFolderIds', $root->getIds(), IQueryBuilder::PARAM_INT_ARRAY);

View File

@ -10,7 +10,7 @@ use OCP\ITags;
trait TimelineQueryFilters trait TimelineQueryFilters
{ {
public function transformFavoriteFilter(IQueryBuilder &$query, bool $aggregate) public function transformFavoriteFilter(IQueryBuilder &$query, bool $aggregate): void
{ {
if (Util::isLoggedIn()) { if (Util::isLoggedIn()) {
$query->innerJoin('m', 'vcategory_to_object', 'vcoi', $query->expr()->andX( $query->innerJoin('m', 'vcategory_to_object', 'vcoi', $query->expr()->andX(
@ -20,7 +20,7 @@ trait TimelineQueryFilters
} }
} }
public function addFavoriteTag(IQueryBuilder &$query) public function addFavoriteTag(IQueryBuilder &$query): void
{ {
if (Util::isLoggedIn()) { if (Util::isLoggedIn()) {
$query->leftJoin('m', 'vcategory_to_object', 'vco', $query->expr()->andX( $query->leftJoin('m', 'vcategory_to_object', 'vco', $query->expr()->andX(
@ -31,12 +31,12 @@ trait TimelineQueryFilters
} }
} }
public function transformVideoFilter(IQueryBuilder &$query, bool $aggregate) public function transformVideoFilter(IQueryBuilder &$query, bool $aggregate): void
{ {
$query->andWhere($query->expr()->eq('m.isvideo', $query->expr()->literal(1))); $query->andWhere($query->expr()->eq('m.isvideo', $query->expr()->literal(1)));
} }
public function transformLimit(IQueryBuilder &$query, bool $aggregate, int $limit) public function transformLimit(IQueryBuilder &$query, bool $aggregate, int $limit): void
{ {
if ($limit >= 1 || $limit <= 100) { if ($limit >= 1 || $limit <= 100) {
$query->setMaxResults($limit); $query->setMaxResults($limit);

View File

@ -17,7 +17,7 @@ trait TimelineQueryFolders
* *
* @param TimelineRoot $root The root to use for the query * @param TimelineRoot $root The root to use for the query
*/ */
public function getRootPreviews(TimelineRoot $root) public function getRootPreviews(TimelineRoot $root): array
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();

View File

@ -6,7 +6,7 @@ namespace OCA\Memories\Db;
trait TimelineQueryLivePhoto trait TimelineQueryLivePhoto
{ {
public function getLivePhotos(int $fileid) public function getLivePhotos(int $fileid): array
{ {
$qb = $this->connection->getQueryBuilder(); $qb = $this->connection->getQueryBuilder();
$qb->select('lp.fileid', 'lp.liveid') $qb->select('lp.fileid', 'lp.liveid')

View File

@ -13,7 +13,7 @@ trait TimelineQueryMap
protected IDBConnection $connection; protected IDBConnection $connection;
public function transformMapBoundsFilter(IQueryBuilder &$query, bool $aggregate, string $bounds, string $table = 'm') public function transformMapBoundsFilter(IQueryBuilder &$query, bool $aggregate, string $bounds, string $table = 'm'): void
{ {
$bounds = explode(',', $bounds); $bounds = explode(',', $bounds);
$bounds = array_map('floatval', $bounds); $bounds = array_map('floatval', $bounds);
@ -84,7 +84,7 @@ trait TimelineQueryMap
return $clusters; return $clusters;
} }
public function getMapClusterPreviews(array $clusterIds) public function getMapClusterPreviews(array $clusterIds): array
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();

View File

@ -8,7 +8,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
trait TimelineQueryNativeX trait TimelineQueryNativeX
{ {
public function transformNativeQuery(IQueryBuilder &$query, bool $aggregate) public function transformNativeQuery(IQueryBuilder &$query, bool $aggregate): void
{ {
if (!$aggregate) { if (!$aggregate) {
$query->addSelect('m.epoch', 'f.size', 'm.buid'); $query->addSelect('m.epoch', 'f.size', 'm.buid');

View File

@ -23,7 +23,7 @@ class TimelineRoot
* *
* @throws \Exception if node is not valid readable folder * @throws \Exception if node is not valid readable folder
*/ */
public function addFolder(FileInfo $info) public function addFolder(FileInfo $info): void
{ {
$path = $info->getPath(); $path = $info->getPath();
@ -42,7 +42,7 @@ class TimelineRoot
/** /**
* Add mountpoints recursively. * Add mountpoints recursively.
*/ */
public function addMountPoints() public function addMountPoints(): void
{ {
$manager = \OC\Files\Filesystem::getMountManager(); $manager = \OC\Files\Filesystem::getMountManager();
foreach ($this->folderPaths as $id => $folderPath) { foreach ($this->folderPaths as $id => $folderPath) {
@ -67,7 +67,7 @@ class TimelineRoot
* *
* @param string[] $paths The paths to exclude * @param string[] $paths The paths to exclude
*/ */
public function excludePaths(array $paths) public function excludePaths(array $paths): void
{ {
foreach ($paths as $path) { foreach ($paths as $path) {
foreach ($this->folderPaths as $id => $folderPath) { foreach ($this->folderPaths as $id => $folderPath) {
@ -87,7 +87,7 @@ class TimelineRoot
* *
* @param string $path The new base path * @param string $path The new base path
*/ */
public function baseChange(string $path) public function baseChange(string $path): void
{ {
foreach ($this->folderPaths as $id => $folderPath) { foreach ($this->folderPaths as $id => $folderPath) {
if (!str_starts_with($folderPath.'/', $path.'/')) { if (!str_starts_with($folderPath.'/', $path.'/')) {
@ -101,11 +101,17 @@ class TimelineRoot
return $this->folderPaths[$id]; return $this->folderPaths[$id];
} }
public function getIds() /**
* @return int[]
*/
public function getIds(): array
{ {
return array_keys($this->folderPaths); return array_keys($this->folderPaths);
} }
/**
* @return null|int
*/
public function getOneId() public function getOneId()
{ {
return array_key_first($this->folders); return array_key_first($this->folders);
@ -116,12 +122,12 @@ class TimelineRoot
return $this->folders[$id]; return $this->folders[$id];
} }
public function isEmpty() public function isEmpty(): bool
{ {
return empty($this->folderPaths); return empty($this->folderPaths);
} }
private function setFolder(int $id, ?FileInfo $fileInfo, ?string $path) private function setFolder(int $id, ?FileInfo $fileInfo, ?string $path): void
{ {
if (null !== $path) { if (null !== $path) {
$this->folderPaths[$id] = $path; $this->folderPaths[$id] = $path;

View File

@ -192,7 +192,7 @@ class TimelineWrite
/** /**
* Remove a file from the exif database. * Remove a file from the exif database.
*/ */
public function deleteFile(File &$file) public function deleteFile(File &$file): void
{ {
// Get full record // Get full record
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -255,7 +255,7 @@ class TimelineWrite
/** /**
* Clear the entire index. Does not need confirmation! * Clear the entire index. Does not need confirmation!
*/ */
public function clear() public function clear(): void
{ {
$p = $this->connection->getDatabasePlatform(); $p = $this->connection->getDatabasePlatform();
foreach (array_merge(DELETE_TABLES, TRUNCATE_TABLES) as $table) { foreach (array_merge(DELETE_TABLES, TRUNCATE_TABLES) as $table) {

View File

@ -22,7 +22,7 @@ trait TimelineWriteOrphans
*/ */
public function orphanAll(bool $value = true, ?array $fileIds = null, bool $onlyMain = false): int public function orphanAll(bool $value = true, ?array $fileIds = null, bool $onlyMain = false): int
{ {
$do = function (string $table) use ($value, $fileIds) { $do = function (string $table) use ($value, $fileIds): int {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
$query->update($table) $query->update($table)
->set('orphan', $query->createNamedParameter($value, IQueryBuilder::PARAM_BOOL)) ->set('orphan', $query->createNamedParameter($value, IQueryBuilder::PARAM_BOOL))
@ -51,7 +51,7 @@ trait TimelineWriteOrphans
* @param int $txnSize number of rows to process in a single transaction * @param int $txnSize number of rows to process in a single transaction
* @param \Closure $callback will be passed each row * @param \Closure $callback will be passed each row
*/ */
public function orphanAndRun(array $fields, int $txnSize, \Closure $callback) public function orphanAndRun(array $fields, int $txnSize, \Closure $callback): void
{ {
// Orphan all files. This means if we are interrupted, // Orphan all files. This means if we are interrupted,
// it will lead to a re-index of the whole library! // it will lead to a re-index of the whole library!

View File

@ -156,8 +156,12 @@ trait TimelineWritePlaces
* Read coordinates from array and round to 6 decimal places. * Read coordinates from array and round to 6 decimal places.
* *
* Modifies the array to remove invalid coordinates. * Modifies the array to remove invalid coordinates.
*
* @return (null|float)[]
*
* @psalm-return list{float|null, float|null}
*/ */
private static function readCoord(array &$exif) private static function readCoord(array &$exif): array
{ {
$lat = \array_key_exists(LAT_KEY, $exif) ? round((float) $exif[LAT_KEY], 6) : null; $lat = \array_key_exists(LAT_KEY, $exif) ? round((float) $exif[LAT_KEY], 6) : null;
$lon = \array_key_exists(LON_KEY, $exif) ? round((float) $exif[LON_KEY], 6) : null; $lon = \array_key_exists(LON_KEY, $exif) ? round((float) $exif[LON_KEY], 6) : null;

View File

@ -19,7 +19,7 @@ class Exif
private static $staticPipes; private static $staticPipes;
private static $noStaticProc = false; private static $noStaticProc = false;
public static function closeStaticExiftoolProc() public static function closeStaticExiftoolProc(): void
{ {
try { try {
if (self::$staticProc) { if (self::$staticProc) {
@ -35,13 +35,13 @@ class Exif
} }
} }
public static function restartStaticExiftoolProc() public static function restartStaticExiftoolProc(): void
{ {
self::closeStaticExiftoolProc(); self::closeStaticExiftoolProc();
self::ensureStaticExiftoolProc(); self::ensureStaticExiftoolProc();
} }
public static function ensureStaticExiftoolProc() public static function ensureStaticExiftoolProc(): void
{ {
if (self::$noStaticProc) { if (self::$noStaticProc) {
return; return;
@ -68,7 +68,7 @@ class Exif
/** /**
* Get exif data as a JSON object from a Nextcloud file. * Get exif data as a JSON object from a Nextcloud file.
*/ */
public static function getExifFromFile(File $file) public static function getExifFromFile(File $file): array
{ {
try { try {
$path = $file->getStorage()->getLocalFile($file->getInternalPath()); $path = $file->getStorage()->getLocalFile($file->getInternalPath());
@ -106,8 +106,10 @@ class Exif
return $exif; return $exif;
} }
/** Get exif data as a JSON object from a local file path */ /**
public static function getExifFromLocalPath(string $path) * Get exif data as a JSON object from a local file path.
*/
public static function getExifFromLocalPath(string $path): array
{ {
if (null !== self::$staticProc) { if (null !== self::$staticProc) {
self::ensureStaticExiftoolProc(); self::ensureStaticExiftoolProc();
@ -298,7 +300,7 @@ class Exif
* *
* @throws \Exception on failure * @throws \Exception on failure
*/ */
public static function setExif(string $path, array $data) public static function setExif(string $path, array $data): void
{ {
$data['SourceFile'] = $path; $data['SourceFile'] = $path;
$raw = json_encode([$data], JSON_UNESCAPED_UNICODE); $raw = json_encode([$data], JSON_UNESCAPED_UNICODE);
@ -328,7 +330,7 @@ class Exif
} }
} }
public static function setFileExif(File $file, array $data) public static function setFileExif(File $file, array $data): void
{ {
// Get path to local file so we can skip reading // Get path to local file so we can skip reading
$path = $file->getStorage()->getLocalFile($file->getInternalPath()); $path = $file->getStorage()->getLocalFile($file->getInternalPath());
@ -345,7 +347,7 @@ class Exif
$file->touch(); $file->touch();
} }
public static function getBinaryExifProp(string $path, string $prop) public static function getBinaryExifProp(string $path, string $prop): string
{ {
$pipes = []; $pipes = [];
$proc = proc_open(array_merge(self::getExiftool(), [$prop, '-n', '-b', $path]), [ $proc = proc_open(array_merge(self::getExiftool(), [$prop, '-n', '-b', $path]), [
@ -368,7 +370,7 @@ class Exif
} }
} }
public static function getExifWithDuplicates(string $path) public static function getExifWithDuplicates(string $path): array
{ {
return self::getExifFromLocalPathWithSeparateProc($path, ['-U', '-G4']); return self::getExifFromLocalPathWithSeparateProc($path, ['-U', '-G4']);
} }
@ -378,8 +380,10 @@ class Exif
return BinExt::getExiftool(); return BinExt::getExiftool();
} }
/** Initialize static exiftool process for local reads */ /**
private static function initializeStaticExiftoolProc() * Initialize static exiftool process for local reads.
*/
private static function initializeStaticExiftoolProc(): void
{ {
self::closeStaticExiftoolProc(); self::closeStaticExiftoolProc();
self::$staticProc = proc_open(array_merge(self::getExiftool(), ['-stay_open', 'true', '-@', '-']), [ self::$staticProc = proc_open(array_merge(self::getExiftool(), ['-stay_open', 'true', '-@', '-']), [
@ -397,7 +401,7 @@ class Exif
* @param int $timeout milliseconds * @param int $timeout milliseconds
* @param string $delimiter null for eof * @param string $delimiter null for eof
*/ */
private static function readOrTimeout($handle, int $timeout, ?string $delimiter = null) private static function readOrTimeout($handle, int $timeout, ?string $delimiter = null): string
{ {
$buf = ''; $buf = '';
$waitedMs = 0; $waitedMs = 0;
@ -420,7 +424,7 @@ class Exif
return $buf; return $buf;
} }
private static function getExifFromLocalPathWithStaticProc(string $path) private static function getExifFromLocalPathWithStaticProc(string $path): array
{ {
$args = implode("\n", self::EXIFTOOL_ARGS); $args = implode("\n", self::EXIFTOOL_ARGS);
fwrite(self::$staticPipes[0], "{$path}\n{$args}\n-execute\n"); fwrite(self::$staticPipes[0], "{$path}\n{$args}\n-execute\n");
@ -442,7 +446,7 @@ class Exif
} }
} }
private static function getExifFromLocalPathWithSeparateProc(string $path, array $extraArgs = []) private static function getExifFromLocalPathWithSeparateProc(string $path, array $extraArgs = []): array
{ {
$pipes = []; $pipes = [];
$proc = proc_open(array_merge(self::getExiftool(), self::EXIFTOOL_ARGS, $extraArgs, [$path]), [ $proc = proc_open(array_merge(self::getExiftool(), self::EXIFTOOL_ARGS, $extraArgs, [$path]), [
@ -468,7 +472,7 @@ class Exif
} }
/** Get json array from stdout of exiftool */ /** Get json array from stdout of exiftool */
private static function processStdout(string $stdout) private static function processStdout(string $stdout): array
{ {
$json = json_decode($stdout, true); $json = json_decode($stdout, true);
if (!$json) { if (!$json) {

View File

@ -26,6 +26,9 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener; use OCP\EventDispatcher\IEventListener;
use OCP\ISession; use OCP\ISession;
/**
* @template-implements IEventListener<Event>
*/
class BeforeTemplateListener implements IEventListener class BeforeTemplateListener implements IEventListener
{ {
private ISession $session; private ISession $session;

View File

@ -27,6 +27,9 @@ use OCP\EventDispatcher\IEventListener;
use OCP\Files\Events\Node\NodeDeletedEvent; use OCP\Files\Events\Node\NodeDeletedEvent;
use OCP\Files\Folder; use OCP\Files\Folder;
/**
* @template-implements IEventListener<Event>
*/
class PostDeleteListener implements IEventListener class PostDeleteListener implements IEventListener
{ {
private TimelineWrite $util; private TimelineWrite $util;

View File

@ -25,6 +25,9 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener; use OCP\EventDispatcher\IEventListener;
use OCP\ISession; use OCP\ISession;
/**
* @template-implements IEventListener<Event>
*/
class PostLogoutListener implements IEventListener class PostLogoutListener implements IEventListener
{ {
public const CLEAR_CACHE_KEY = 'memories_clear_cache'; public const CLEAR_CACHE_KEY = 'memories_clear_cache';

View File

@ -29,6 +29,9 @@ use OCP\Files\Events\Node\NodeTouchedEvent;
use OCP\Files\Events\Node\NodeWrittenEvent; use OCP\Files\Events\Node\NodeWrittenEvent;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/**
* @template-implements IEventListener<Event>
*/
class PostWriteListener implements IEventListener class PostWriteListener implements IEventListener
{ {
private TimelineWrite $timelineWrite; private TimelineWrite $timelineWrite;

View File

@ -164,7 +164,7 @@ class BinExt
return "http://{$connect}/{$client}{$path}/{$profile}"; return "http://{$connect}/{$client}{$path}/{$profile}";
} }
public static function getGoVodConfig($local = false) public static function getGoVodConfig(bool $local = false): array
{ {
// Get config from system values // Get config from system values
$env = [ $env = [
@ -205,7 +205,7 @@ class BinExt
/** /**
* Get temp binary for go-vod. * Get temp binary for go-vod.
*/ */
public static function getGoVodBin() public static function getGoVodBin(): string
{ {
$path = Util::getSystemConfig('memories.vod.path'); $path = Util::getSystemConfig('memories.vod.path');
@ -332,8 +332,10 @@ class BinExt
return $version; return $version;
} }
/** POST a new configuration to go-vod */ /**
public static function configureGoVod() * POST a new configuration to go-vod.
*/
public static function configureGoVod(): bool
{ {
// Get config // Get config
$config = self::getGoVodConfig(); $config = self::getGoVodConfig();
@ -412,7 +414,7 @@ class BinExt
return $ffmpegPath; return $ffmpegPath;
} }
public static function testFFmpeg(string $path, string $name) public static function testFFmpeg(string $path, string $name): string
{ {
$version = shell_exec("{$path} -version"); $version = shell_exec("{$path} -version");
if (!preg_match("/{$name} version \\S*/", $version, $matches)) { if (!preg_match("/{$name} version \\S*/", $version, $matches)) {
@ -422,12 +424,12 @@ class BinExt
return explode(' ', $matches[0])[2]; return explode(' ', $matches[0])[2];
} }
public static function testSystemPerl(string $path): string public static function testSystemPerl(string $path): ?string
{ {
if (($out = shell_exec("{$path} -e 'print \"OK\";'")) !== 'OK') { if (($out = shell_exec("{$path} -e 'print \"OK\";'")) !== 'OK') {
throw new \Exception('Failed to run test perl script: '.$out); throw new \Exception('Failed to run test perl script: '.$out);
} }
return shell_exec("{$path} -e 'print $^V;'"); return shell_exec("{$path} -e 'print $^V;'") ?: null;
} }
} }

View File

@ -123,7 +123,7 @@ class FileRobotImageState
} }
} }
private function _set(array $parent, string $key, string $ckey = null) private function _set(array $parent, string $key, string $ckey = null): void
{ {
$ckey ??= $key; $ckey ??= $key;
if (\array_key_exists($key, $parent)) { if (\array_key_exists($key, $parent)) {
@ -146,7 +146,7 @@ class FileRobotMagick
$this->state = new FileRobotImageState($state); $this->state = new FileRobotImageState($state);
} }
public function apply() public function apply(): \Imagick
{ {
// Ensure the image is in the correct colorspace // Ensure the image is in the correct colorspace
if (\Imagick::COLORSPACE_SRGB !== $this->image->getColorspace()) { if (\Imagick::COLORSPACE_SRGB !== $this->image->getColorspace()) {
@ -179,7 +179,7 @@ class FileRobotMagick
return $this->image; return $this->image;
} }
protected function applyCrop() protected function applyCrop(): void
{ {
if ($this->state->cropX || $this->state->cropY || $this->state->cropWidth || $this->state->cropHeight) { if ($this->state->cropX || $this->state->cropY || $this->state->cropWidth || $this->state->cropHeight) {
$iw = $this->image->getImageWidth(); $iw = $this->image->getImageWidth();
@ -193,7 +193,7 @@ class FileRobotMagick
} }
} }
protected function applyFlipRotation() protected function applyFlipRotation(): void
{ {
if ($this->state->isFlippedX) { if ($this->state->isFlippedX) {
$this->image->flopImage(); $this->image->flopImage();
@ -206,7 +206,7 @@ class FileRobotMagick
} }
} }
protected function applyResize() protected function applyResize(): void
{ {
if ($this->state->resizeWidth || $this->state->resizeHeight) { if ($this->state->resizeWidth || $this->state->resizeHeight) {
$this->image->resizeImage( $this->image->resizeImage(
@ -218,7 +218,7 @@ class FileRobotMagick
} }
} }
protected function applyBrighten(?float $value = null) protected function applyBrighten(?float $value = null): void
{ {
$brightness = $value ?? $this->state->brightness ?? 0; $brightness = $value ?? $this->state->brightness ?? 0;
if (0 === $brightness) { if (0 === $brightness) {
@ -229,7 +229,7 @@ class FileRobotMagick
$this->image->evaluateImage(\Imagick::EVALUATE_ADD, $brightness * 255 * 255, \Imagick::CHANNEL_ALL); $this->image->evaluateImage(\Imagick::EVALUATE_ADD, $brightness * 255 * 255, \Imagick::CHANNEL_ALL);
} }
protected function applyContrast(?float $value = null) protected function applyContrast(?float $value = null): void
{ {
$contrast = $value ?? $this->state->contrast ?? 0; $contrast = $value ?? $this->state->contrast ?? 0;
if (0 === $contrast) { if (0 === $contrast) {
@ -246,7 +246,7 @@ class FileRobotMagick
$this->image->functionImage(\Imagick::FUNCTION_POLYNOMIAL, [$m, $c], \Imagick::CHANNEL_ALL); $this->image->functionImage(\Imagick::FUNCTION_POLYNOMIAL, [$m, $c], \Imagick::CHANNEL_ALL);
} }
protected function applyHSV(?float $hue = null, ?float $saturation = null, ?float $value = null) protected function applyHSV(?float $hue = null, ?float $saturation = null, ?float $value = null): void
{ {
$hue ??= $this->state->hue ?? 0; $hue ??= $this->state->hue ?? 0;
$saturation ??= $this->state->saturation ?? 0; $saturation ??= $this->state->saturation ?? 0;
@ -274,18 +274,17 @@ class FileRobotMagick
$bg = 0.587 * $v - 0.586 * $vsu - 1.05 * $vsw; $bg = 0.587 * $v - 0.586 * $vsu - 1.05 * $vsw;
$bb = 0.114 * $v + 0.886 * $vsu - 0.2 * $vsw; $bb = 0.114 * $v + 0.886 * $vsu - 0.2 * $vsw;
$colorMatrix = [ /** @psalm-suppress InvalidArgument */
$this->image->colorMatrixImage([
$rr, $rg, $rb, 0, 0, $rr, $rg, $rb, 0, 0,
$gr, $gg, $gb, 0, 0, $gr, $gg, $gb, 0, 0,
$br, $bg, $bb, 0, 0, $br, $bg, $bb, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
]; ]);
$this->image->colorMatrixImage($colorMatrix);
} }
protected function applyBlur() protected function applyBlur(): void
{ {
if ($this->state->blurRadius <= 0) { if ($this->state->blurRadius <= 0) {
return; return;
@ -296,7 +295,7 @@ class FileRobotMagick
$this->image->blurImage(0, $sigma); $this->image->blurImage(0, $sigma);
} }
protected function applyWarmth() protected function applyWarmth(): void
{ {
// https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/finetunes/Warmth.js#L17-L28 // https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/finetunes/Warmth.js#L17-L28
$warmth = ($this->state->warmth ?? 0); $warmth = ($this->state->warmth ?? 0);
@ -310,20 +309,21 @@ class FileRobotMagick
} }
// https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/components/tools/Filters/Filters.constants.js#L8 // https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/components/tools/Filters/Filters.constants.js#L8
protected function applyFilterInvert() protected function applyFilterInvert(): void
{ {
$this->image->negateImage(false); $this->image->negateImage(false);
} }
protected function applyFilterBlackAndWhite() protected function applyFilterBlackAndWhite(): void
{ {
// https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BlackAndWhite.js // https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BlackAndWhite.js
$this->image->thresholdImage(100 * 255); $this->image->thresholdImage(100 * 255);
} }
protected function applyFilterSepia() protected function applyFilterSepia(): void
{ {
// https://github.com/konvajs/konva/blob/master/src/filters/Sepia.ts // https://github.com/konvajs/konva/blob/master/src/filters/Sepia.ts
/** @psalm-suppress InvalidArgument */
$this->image->colorMatrixImage([ $this->image->colorMatrixImage([
0.393, 0.769, 0.189, 0, 0, 0.393, 0.769, 0.189, 0, 0,
0.349, 0.686, 0.168, 0, 0, 0.349, 0.686, 0.168, 0, 0,
@ -333,267 +333,267 @@ class FileRobotMagick
]); ]);
} }
protected function applyFilterSolarize() protected function applyFilterSolarize(): void
{ {
// https://github.com/konvajs/konva/blob/master/src/filters/Solarize.ts // https://github.com/konvajs/konva/blob/master/src/filters/Solarize.ts
$this->image->solarizeImage(128 * 255); $this->image->solarizeImage(128 * 255);
} }
protected function applyFilterClarendon() protected function applyFilterClarendon(): void
{ {
$this->applyBaseFilterBrightness(0.1); $this->applyBaseFilterBrightness(0.1);
$this->applyBaseFilterContrast(0.1); $this->applyBaseFilterContrast(0.1);
$this->applyBaseFilterSaturation(0.15); $this->applyBaseFilterSaturation(0.15);
} }
protected function applyFilterGingham() protected function applyFilterGingham(): void
{ {
$this->applyBaseFilterSepia(0.04); $this->applyBaseFilterSepia(0.04);
$this->applyBaseFilterContrast(-0.15); $this->applyBaseFilterContrast(-0.15);
} }
protected function applyFilterMoon() protected function applyFilterMoon(): void
{ {
$this->applyBaseFilterGrayscale(); $this->applyBaseFilterGrayscale();
$this->applyBaseFilterBrightness(0.1); $this->applyBaseFilterBrightness(0.1);
} }
protected function applyFilterLark() protected function applyFilterLark(): void
{ {
$this->applyBaseFilterBrightness(0.08); $this->applyBaseFilterBrightness(0.08);
$this->applyBaseFilterAdjustRGB(1, 1.03, 1.05); $this->applyBaseFilterAdjustRGB(1, 1.03, 1.05);
$this->applyBaseFilterSaturation(0.12); $this->applyBaseFilterSaturation(0.12);
} }
protected function applyFilterReyes() protected function applyFilterReyes(): void
{ {
$this->applyBaseFilterSepia(0.4); $this->applyBaseFilterSepia(0.4);
$this->applyBaseFilterBrightness(0.13); $this->applyBaseFilterBrightness(0.13);
$this->applyBaseFilterContrast(-0.05); $this->applyBaseFilterContrast(-0.05);
} }
protected function applyFilterJuno() protected function applyFilterJuno(): void
{ {
$this->applyBaseFilterAdjustRGB(1.01, 1.04, 1); $this->applyBaseFilterAdjustRGB(1.01, 1.04, 1);
$this->applyBaseFilterSaturation(0.3); $this->applyBaseFilterSaturation(0.3);
} }
protected function applyFilterSlumber() protected function applyFilterSlumber(): void
{ {
$this->applyBaseFilterBrightness(0.1); $this->applyBaseFilterBrightness(0.1);
$this->applyBaseFilterSaturation(-0.5); $this->applyBaseFilterSaturation(-0.5);
} }
protected function applyFilterCrema() protected function applyFilterCrema(): void
{ {
$this->applyBaseFilterAdjustRGB(1.04, 1, 1.02); $this->applyBaseFilterAdjustRGB(1.04, 1, 1.02);
$this->applyBaseFilterSaturation(-0.05); $this->applyBaseFilterSaturation(-0.05);
} }
protected function applyFilterLudwig() protected function applyFilterLudwig(): void
{ {
$this->applyBaseFilterBrightness(0.05); $this->applyBaseFilterBrightness(0.05);
$this->applyBaseFilterSaturation(-0.03); $this->applyBaseFilterSaturation(-0.03);
} }
protected function applyFilterAden() protected function applyFilterAden(): void
{ {
$this->applyBaseFilterColorFilter(228, 130, 225, 0.13); $this->applyBaseFilterColorFilter(228, 130, 225, 0.13);
$this->applyBaseFilterSaturation(-0.2); $this->applyBaseFilterSaturation(-0.2);
} }
protected function applyFilterPerpetua() protected function applyFilterPerpetua(): void
{ {
$this->applyBaseFilterAdjustRGB(1.05, 1.1, 1); $this->applyBaseFilterAdjustRGB(1.05, 1.1, 1);
} }
protected function applyFilterAmaro() protected function applyFilterAmaro(): void
{ {
$this->applyBaseFilterSaturation(0.3); $this->applyBaseFilterSaturation(0.3);
$this->applyBaseFilterBrightness(0.15); $this->applyBaseFilterBrightness(0.15);
} }
protected function applyFilterMayfair() protected function applyFilterMayfair(): void
{ {
$this->applyBaseFilterColorFilter(230, 115, 108, 0.05); $this->applyBaseFilterColorFilter(230, 115, 108, 0.05);
$this->applyBaseFilterSaturation(0.15); $this->applyBaseFilterSaturation(0.15);
} }
protected function applyFilterRise() protected function applyFilterRise(): void
{ {
$this->applyBaseFilterColorFilter(255, 170, 0, 0.1); $this->applyBaseFilterColorFilter(255, 170, 0, 0.1);
$this->applyBaseFilterBrightness(0.09); $this->applyBaseFilterBrightness(0.09);
$this->applyBaseFilterSaturation(0.1); $this->applyBaseFilterSaturation(0.1);
} }
protected function applyFilterHudson() protected function applyFilterHudson(): void
{ {
$this->applyBaseFilterAdjustRGB(1, 1, 1.25); $this->applyBaseFilterAdjustRGB(1, 1, 1.25);
$this->applyBaseFilterContrast(0.1); $this->applyBaseFilterContrast(0.1);
$this->applyBaseFilterBrightness(0.15); $this->applyBaseFilterBrightness(0.15);
} }
protected function applyFilterValencia() protected function applyFilterValencia(): void
{ {
$this->applyBaseFilterColorFilter(255, 225, 80, 0.08); $this->applyBaseFilterColorFilter(255, 225, 80, 0.08);
$this->applyBaseFilterSaturation(0.1); $this->applyBaseFilterSaturation(0.1);
$this->applyBaseFilterContrast(0.05); $this->applyBaseFilterContrast(0.05);
} }
protected function applyFilterXpro2() protected function applyFilterXpro2(): void
{ {
$this->applyBaseFilterColorFilter(255, 255, 0, 0.07); $this->applyBaseFilterColorFilter(255, 255, 0, 0.07);
$this->applyBaseFilterSaturation(0.2); $this->applyBaseFilterSaturation(0.2);
$this->applyBaseFilterContrast(0.15); $this->applyBaseFilterContrast(0.15);
} }
protected function applyFilterSierra() protected function applyFilterSierra(): void
{ {
$this->applyBaseFilterContrast(-0.15); $this->applyBaseFilterContrast(-0.15);
$this->applyBaseFilterSaturation(0.1); $this->applyBaseFilterSaturation(0.1);
} }
protected function applyFilterWillow() protected function applyFilterWillow(): void
{ {
$this->applyBaseFilterGrayscale(); $this->applyBaseFilterGrayscale();
$this->applyBaseFilterColorFilter(100, 28, 210, 0.03); $this->applyBaseFilterColorFilter(100, 28, 210, 0.03);
$this->applyBaseFilterBrightness(0.1); $this->applyBaseFilterBrightness(0.1);
} }
protected function applyFilterLoFi() protected function applyFilterLoFi(): void
{ {
$this->applyBaseFilterContrast(0.15); $this->applyBaseFilterContrast(0.15);
$this->applyBaseFilterSaturation(0.2); $this->applyBaseFilterSaturation(0.2);
} }
protected function applyFilterInkwell() protected function applyFilterInkwell(): void
{ {
$this->applyBaseFilterGrayscale(); $this->applyBaseFilterGrayscale();
} }
protected function applyFilterHefe() protected function applyFilterHefe(): void
{ {
$this->applyBaseFilterContrast(0.1); $this->applyBaseFilterContrast(0.1);
$this->applyBaseFilterSaturation(0.15); $this->applyBaseFilterSaturation(0.15);
} }
protected function applyFilterNashville() protected function applyFilterNashville(): void
{ {
$this->applyBaseFilterColorFilter(220, 115, 188, 0.12); $this->applyBaseFilterColorFilter(220, 115, 188, 0.12);
$this->applyBaseFilterContrast(-0.05); $this->applyBaseFilterContrast(-0.05);
} }
protected function applyFilterStinson() protected function applyFilterStinson(): void
{ {
$this->applyBaseFilterBrightness(0.1); $this->applyBaseFilterBrightness(0.1);
$this->applyBaseFilterSepia(0.3); $this->applyBaseFilterSepia(0.3);
} }
protected function applyFilterVesper() protected function applyFilterVesper(): void
{ {
$this->applyBaseFilterColorFilter(255, 225, 0, 0.05); $this->applyBaseFilterColorFilter(255, 225, 0, 0.05);
$this->applyBaseFilterBrightness(0.06); $this->applyBaseFilterBrightness(0.06);
$this->applyBaseFilterContrast(0.06); $this->applyBaseFilterContrast(0.06);
} }
protected function applyFilterEarlybird() protected function applyFilterEarlybird(): void
{ {
$this->applyBaseFilterColorFilter(255, 165, 40, 0.2); $this->applyBaseFilterColorFilter(255, 165, 40, 0.2);
} }
protected function applyFilterBrannan() protected function applyFilterBrannan(): void
{ {
$this->applyBaseFilterContrast(0.2); $this->applyBaseFilterContrast(0.2);
$this->applyBaseFilterColorFilter(140, 10, 185, 0.1); $this->applyBaseFilterColorFilter(140, 10, 185, 0.1);
} }
protected function applyFilterSutro() protected function applyFilterSutro(): void
{ {
$this->applyBaseFilterBrightness(-0.1); $this->applyBaseFilterBrightness(-0.1);
$this->applyBaseFilterContrast(-0.1); $this->applyBaseFilterContrast(-0.1);
} }
protected function applyFilterToaster() protected function applyFilterToaster(): void
{ {
$this->applyBaseFilterSepia(0.1); $this->applyBaseFilterSepia(0.1);
$this->applyBaseFilterColorFilter(255, 145, 0, 0.2); $this->applyBaseFilterColorFilter(255, 145, 0, 0.2);
} }
protected function applyFilterWalden() protected function applyFilterWalden(): void
{ {
$this->applyBaseFilterBrightness(0.1); $this->applyBaseFilterBrightness(0.1);
$this->applyBaseFilterColorFilter(255, 255, 0, 0.2); $this->applyBaseFilterColorFilter(255, 255, 0, 0.2);
} }
protected function applyFilterNinteenSeventySeven() protected function applyFilterNinteenSeventySeven(): void
{ {
$this->applyBaseFilterColorFilter(255, 25, 0, 0.15); $this->applyBaseFilterColorFilter(255, 25, 0, 0.15);
$this->applyBaseFilterBrightness(0.1); $this->applyBaseFilterBrightness(0.1);
} }
protected function applyFilterKelvin() protected function applyFilterKelvin(): void
{ {
$this->applyBaseFilterColorFilter(255, 140, 0, 0.1); $this->applyBaseFilterColorFilter(255, 140, 0, 0.1);
$this->applyBaseFilterAdjustRGB(1.15, 1.05, 1); $this->applyBaseFilterAdjustRGB(1.15, 1.05, 1);
$this->applyBaseFilterSaturation(0.35); $this->applyBaseFilterSaturation(0.35);
} }
protected function applyFilterMaven() protected function applyFilterMaven(): void
{ {
$this->applyBaseFilterColorFilter(225, 240, 0, 0.1); $this->applyBaseFilterColorFilter(225, 240, 0, 0.1);
$this->applyBaseFilterSaturation(0.25); $this->applyBaseFilterSaturation(0.25);
$this->applyBaseFilterContrast(0.05); $this->applyBaseFilterContrast(0.05);
} }
protected function applyFilterGinza() protected function applyFilterGinza(): void
{ {
$this->applyBaseFilterSepia(0.06); $this->applyBaseFilterSepia(0.06);
$this->applyBaseFilterBrightness(0.1); $this->applyBaseFilterBrightness(0.1);
} }
protected function applyFilterSkyline() protected function applyFilterSkyline(): void
{ {
$this->applyBaseFilterSaturation(0.35); $this->applyBaseFilterSaturation(0.35);
$this->applyBaseFilterBrightness(0.1); $this->applyBaseFilterBrightness(0.1);
} }
protected function applyFilterDogpatch() protected function applyFilterDogpatch(): void
{ {
$this->applyBaseFilterContrast(0.15); $this->applyBaseFilterContrast(0.15);
$this->applyBaseFilterBrightness(0.1); $this->applyBaseFilterBrightness(0.1);
} }
protected function applyFilterBrooklyn() protected function applyFilterBrooklyn(): void
{ {
$this->applyBaseFilterColorFilter(25, 240, 252, 0.05); $this->applyBaseFilterColorFilter(25, 240, 252, 0.05);
$this->applyBaseFilterSepia(0.3); $this->applyBaseFilterSepia(0.3);
} }
protected function applyFilterHelena() protected function applyFilterHelena(): void
{ {
$this->applyBaseFilterColorFilter(208, 208, 86, 0.2); $this->applyBaseFilterColorFilter(208, 208, 86, 0.2);
$this->applyBaseFilterContrast(0.15); $this->applyBaseFilterContrast(0.15);
} }
protected function applyFilterAshby() protected function applyFilterAshby(): void
{ {
$this->applyBaseFilterColorFilter(255, 160, 25, 0.1); $this->applyBaseFilterColorFilter(255, 160, 25, 0.1);
$this->applyBaseFilterBrightness(0.1); $this->applyBaseFilterBrightness(0.1);
} }
protected function applyFilterCharmes() protected function applyFilterCharmes(): void
{ {
$this->applyBaseFilterColorFilter(255, 50, 80, 0.12); $this->applyBaseFilterColorFilter(255, 50, 80, 0.12);
$this->applyBaseFilterContrast(0.05); $this->applyBaseFilterContrast(0.05);
} }
protected function applyBaseFilterBrightness(float $value) protected function applyBaseFilterBrightness(float $value): void
{ {
// https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L2 // https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L2
$this->applyBrighten($value); $this->applyBrighten($value);
} }
protected function applyBaseFilterContrast(float $value) protected function applyBaseFilterContrast(float $value): void
{ {
// https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L14 // https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L14
$value *= 255; $value *= 255;
@ -606,16 +606,17 @@ class FileRobotMagick
$this->image->functionImage(\Imagick::FUNCTION_POLYNOMIAL, [$m, $c], \Imagick::CHANNEL_ALL); $this->image->functionImage(\Imagick::FUNCTION_POLYNOMIAL, [$m, $c], \Imagick::CHANNEL_ALL);
} }
protected function applyBaseFilterSaturation(float $value) protected function applyBaseFilterSaturation(float $value): void
{ {
// https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L24 // https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L24
$this->applyHSV(0, $value, 0); // lazy $this->applyHSV(0, $value, 0); // lazy
} }
protected function applyBaseFilterGrayscale() protected function applyBaseFilterGrayscale(): void
{ {
// https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L38 // https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L38
// y = 0.2126 * r + 0.7152 * g + 0.0722 * b; // y = 0.2126 * r + 0.7152 * g + 0.0722 * b;
/** @psalm-suppress InvalidArgument */
$this->image->colorMatrixImage([ $this->image->colorMatrixImage([
0.2126, 0.7152, 0.0722, 0, 0, 0.2126, 0.7152, 0.0722, 0, 0,
0.2126, 0.7152, 0.0722, 0, 0, 0.2126, 0.7152, 0.0722, 0, 0,
@ -625,9 +626,10 @@ class FileRobotMagick
]); ]);
} }
protected function applyBaseFilterSepia(float $value) protected function applyBaseFilterSepia(float $value): void
{ {
// https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L46 // https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L46
/** @psalm-suppress InvalidArgument */
$this->image->colorMatrixImage([ $this->image->colorMatrixImage([
1 - 0.607 * $value, 0.769 * $value, 0.189 * $value, 0, 0, 1 - 0.607 * $value, 0.769 * $value, 0.189 * $value, 0, 0,
0.349 * $value, 1 - 0.314 * $value, 0.168 * $value, 0, 0, 0.349 * $value, 1 - 0.314 * $value, 0.168 * $value, 0, 0,
@ -637,9 +639,10 @@ class FileRobotMagick
]); ]);
} }
protected function applyBaseFilterAdjustRGB(float $r, float $g, float $b) protected function applyBaseFilterAdjustRGB(float $r, float $g, float $b): void
{ {
// https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L57 // https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L57
/** @psalm-suppress InvalidArgument */
$this->image->colorMatrixImage([ $this->image->colorMatrixImage([
$r, 0, 0, 0, 0, $r, 0, 0, 0, 0,
0, $g, 0, 0, 0, 0, $g, 0, 0, 0,
@ -649,7 +652,7 @@ class FileRobotMagick
]); ]);
} }
protected function applyBaseFilterColorFilter(float $r, float $g, float $b, float $v) protected function applyBaseFilterColorFilter(float $r, float $g, float $b, float $v): void
{ {
// https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L63 // https://github.com/scaleflex/filerobot-image-editor/blob/7113bf4968d97f41381f4a2965a59defd44562c8/packages/react-filerobot-image-editor/src/custom/filters/BaseFilters.js#L63
// y = x - (x - k) * v = (1 - v) * x + k * v // y = x - (x - k) * v = (1 - v) * x + k * v

View File

@ -153,7 +153,7 @@ class Index
; ;
// Filter out files that are already indexed // Filter out files that are already indexed
$addFilter = static function (string $table, string $alias) use (&$query) { $addFilter = static function (string $table, string $alias) use (&$query): void {
$query->leftJoin('f', $table, $alias, $query->expr()->andX( $query->leftJoin('f', $table, $alias, $query->expr()->andX(
$query->expr()->eq('f.fileid', "{$alias}.fileid"), $query->expr()->eq('f.fileid', "{$alias}.fileid"),
$query->expr()->eq('f.mtime', "{$alias}.mtime"), $query->expr()->eq('f.mtime', "{$alias}.mtime"),
@ -224,7 +224,7 @@ class Index
/** /**
* Get total number of files that are indexed. * Get total number of files that are indexed.
*/ */
public function getIndexedCount() public function getIndexedCount(): int
{ {
$query = $this->db->getQueryBuilder(); $query = $this->db->getQueryBuilder();
$query->select($query->createFunction('COUNT(DISTINCT fileid)')) $query->select($query->createFunction('COUNT(DISTINCT fileid)'))
@ -282,8 +282,10 @@ class Index
return \in_array($file->getMimeType(), Application::VIDEO_MIMES, true); return \in_array($file->getMimeType(), Application::VIDEO_MIMES, true);
} }
/** Log to console if CLI or logger */ /**
private function error(string $message) * Log error to console if CLI or logger.
*/
private function error(string $message): void
{ {
$this->logger->error($message); $this->logger->error($message);
@ -292,8 +294,10 @@ class Index
} }
} }
/** Log to console if CLI */ /**
private function log(string $message, bool $overwrite = false) * Log to console if CLI.
*/
private function log(string $message, bool $overwrite = false): void
{ {
if ($this->output) { if ($this->output) {
if ($overwrite) { if ($overwrite) {

View File

@ -34,8 +34,10 @@ class Places
/** /**
* Make SQL query to detect GIS type. * Make SQL query to detect GIS type.
*
* @psalm-return 0|1|2
*/ */
public function detectGisType() public function detectGisType(): int
{ {
// Make sure database prefix is set // Make sure database prefix is set
$prefix = $this->config->getSystemValue('dbtableprefix', '') ?: ''; $prefix = $this->config->getSystemValue('dbtableprefix', '') ?: '';
@ -83,7 +85,7 @@ class Places
public function geomCount(): int public function geomCount(): int
{ {
try { try {
return $this->connection->executeQuery('SELECT COUNT(osm_id) as c FROM memories_planet_geometry')->fetchOne(); return (int) $this->connection->executeQuery('SELECT COUNT(osm_id) as c FROM memories_planet_geometry')->fetchOne();
} catch (\Exception $e) { } catch (\Exception $e) {
return 0; return 0;
} }
@ -244,7 +246,7 @@ class Places
$txnCount = 0; $txnCount = 0;
// Function to commit the current transaction // Function to commit the current transaction
$transact = function () use (&$txnCount) { $transact = function () use (&$txnCount): void {
if (++$txnCount >= DB_TRANSACTION_SIZE) { if (++$txnCount >= DB_TRANSACTION_SIZE) {
$this->connection->commit(); $this->connection->commit();
$this->connection->beginTransaction(); $this->connection->beginTransaction();
@ -379,7 +381,7 @@ class Places
/** /**
* Recalculate all places for all users. * Recalculate all places for all users.
*/ */
public function recalculateAll() public function recalculateAll(): void
{ {
echo "Recalculating places for all files (do not interrupt this process)...\n"; echo "Recalculating places for all files (do not interrupt this process)...\n";
flush(); flush();

View File

@ -12,7 +12,6 @@ use OCP\App\IAppManager;
use OCP\Files\Node; use OCP\Files\Node;
use OCP\Files\Search\ISearchBinaryOperator; use OCP\Files\Search\ISearchBinaryOperator;
use OCP\Files\Search\ISearchComparison; use OCP\Files\Search\ISearchComparison;
use OCP\IAppConfig;
use OCP\IConfig; use OCP\IConfig;
class Util class Util
@ -23,8 +22,10 @@ class Util
/** /**
* Get host CPU architecture (amd64 or aarch64). * Get host CPU architecture (amd64 or aarch64).
*
* @psalm-return 'aarch64'|'amd64'|null
*/ */
public static function getArch() public static function getArch(): ?string
{ {
$uname = php_uname('m'); $uname = php_uname('m');
if (false !== stripos($uname, 'aarch64') || false !== stripos($uname, 'arm64')) { if (false !== stripos($uname, 'aarch64') || false !== stripos($uname, 'arm64')) {
@ -39,8 +40,10 @@ class Util
/** /**
* Get the libc type for host (glibc or musl). * Get the libc type for host (glibc or musl).
*
* @psalm-return 'glibc'|'musl'|null
*/ */
public static function getLibc() public static function getLibc(): ?string
{ {
if ($ldd = shell_exec('ldd --version 2>&1')) { if ($ldd = shell_exec('ldd --version 2>&1')) {
if (false !== stripos($ldd, 'musl')) { if (false !== stripos($ldd, 'musl')) {
@ -89,8 +92,8 @@ class Util
return false; return false;
} }
$config = \OC::$server->get(IAppConfig::class); $config = \OC::$server->get(IConfig::class);
if ('true' !== $config->getValue('recognize', 'faces.enabled', 'false')) { if ('true' !== $config->getAppValue('recognize', 'faces.enabled', 'false')) {
return false; return false;
} }
@ -192,10 +195,12 @@ class Util
* @param mixed $key Key to set * @param mixed $key Key to set
* @param mixed $value Value to set * @param mixed $value Value to set
*/ */
public static function forceFileInfo(Node &$node, $key, $value) public static function forceFileInfo(Node &$node, $key, $value): void
{ {
/** @var \OC\Files\Node\Node */ /** @var \OC\Files\Node\Node */
$node = $node; $node = $node;
/** @psalm-suppress UndefinedInterfaceMethod */
$node->getFileInfo()[$key] = $value; $node->getFileInfo()[$key] = $value;
} }
@ -205,7 +210,7 @@ class Util
* @param mixed $node File to patch * @param mixed $node File to patch
* @param mixed $permissions Permissions to set * @param mixed $permissions Permissions to set
*/ */
public static function forcePermissions(Node &$node, int $permissions) public static function forcePermissions(Node &$node, int $permissions): void
{ {
self::forceFileInfo($node, 'permissions', $permissions); self::forceFileInfo($node, 'permissions', $permissions);
} }
@ -284,7 +289,7 @@ class Util
* *
* @param $folder Folder to search * @param $folder Folder to search
*/ */
public static function getAnyMedia(\OCP\Files\Folder $folder): Node public static function getAnyMedia(\OCP\Files\Folder $folder): ?Node
{ {
$query = new SearchQuery(new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, [ $query = new SearchQuery(new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, [
new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', 'image/%'), new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', 'image/%'),
@ -338,11 +343,11 @@ class Util
/** /**
* Sanitize a path to keep only ASCII characters and special characters. * Sanitize a path to keep only ASCII characters and special characters.
*/ */
public static function sanitizePath(string $path): string public static function sanitizePath(string $path): ?string
{ {
$path = str_replace("\0", '', $path); // remove null characters $path = str_replace("\0", '', $path); // remove null characters
return mb_ereg_replace('\/\/+', '/', $path); // remove extra slashes return mb_ereg_replace('\/\/+', '/', $path) ?: null; // remove extra slashes
} }
/** /**

View File

@ -32,6 +32,7 @@ trait UtilController
*/ */
public static function guardExDirect(\Closure $closure): Http\Response public static function guardExDirect(\Closure $closure): Http\Response
{ {
/** @psalm-suppress MissingTemplateParam */
return new class($closure) extends Http\Response implements Http\ICallbackResponse { return new class($closure) extends Http\Response implements Http\ICallbackResponse {
private \Closure $_closure; private \Closure $_closure;

38
psalm.xml 100644
View File

@ -0,0 +1,38 @@
<?xml version="1.0"?>
<psalm
totallyTyped="true"
errorLevel="5"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="lib" />
<ignoreFiles>
<directory name="tools" />
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
<extraFiles>
<directory name="../../lib" />
<directory name="../../3rdparty/doctrine" />
<directory name="../../3rdparty/psr" />
<directory name="../../3rdparty/guzzlehttp" />
<directory name="../../3rdparty/doctrine" />
<directory name="../../apps/files/lib/Event" />
</extraFiles>
<issueHandlers>
<UndefinedDocblockClass>
<errorLevel type="suppress">
<referencedClass name="Doctrine\DBAL\Schema\Schema" />
<referencedClass name="Doctrine\DBAL\Schema\SchemaException" />
<referencedClass name="Doctrine\DBAL\Driver\Statement" />
<referencedClass name="Doctrine\DBAL\Schema\Table" />
<referencedClass name="Doctrine\DBAL\Platforms\AbstractPlatform" />
</errorLevel>
</UndefinedDocblockClass>
</issueHandlers>
</psalm>