refactor: apply rector
Some checks are pending
tests / ci (push) Waiting to run

This commit is contained in:
Benjamin Nussbaum 2025-09-24 20:31:32 +02:00
parent c67a182cf2
commit b4b6286172
89 changed files with 672 additions and 666 deletions

View file

@ -23,7 +23,7 @@ class FirmwareCheckCommand extends Command
);
$latestFirmware = Firmware::getLatest();
if ($latestFirmware) {
if ($latestFirmware instanceof Firmware) {
table(
rows: [
['Latest Version', $latestFirmware->version_tag],

View file

@ -42,15 +42,14 @@ class FirmwareUpdateCommand extends Command
label: 'Which devices should be updated?',
options: [
'all' => 'ALL Devices',
...Device::all()->mapWithKeys(function ($device) {
...Device::all()->mapWithKeys(fn ($device): array =>
// without _ returns index
return ["_$device->id" => "$device->name (Current version: $device->last_firmware_version)"];
})->toArray(),
["_$device->id" => "$device->name (Current version: $device->last_firmware_version)"])->toArray(),
],
scroll: 10
);
if (empty($devices)) {
if ($devices === []) {
$this->error('No devices selected. Aborting.');
return;
@ -59,9 +58,7 @@ class FirmwareUpdateCommand extends Command
if (in_array('all', $devices)) {
$devices = Device::pluck('id')->toArray();
} else {
$devices = array_map(function ($selected) {
return (int) str_replace('_', '', $selected);
}, $devices);
$devices = array_map(fn ($selected): int => (int) str_replace('_', '', $selected), $devices);
}
foreach ($devices as $deviceId) {

View file

@ -28,17 +28,17 @@ class MashupCreateCommand extends Command
/**
* Execute the console command.
*/
public function handle()
public function handle(): int
{
// Select device
$device = $this->selectDevice();
if (! $device) {
if (! $device instanceof Device) {
return 1;
}
// Select playlist
$playlist = $this->selectPlaylist($device);
if (! $playlist) {
if (! $playlist instanceof Playlist) {
return 1;
}
@ -87,7 +87,7 @@ class MashupCreateCommand extends Command
$deviceId = $this->choice(
'Select a device',
$devices->mapWithKeys(fn ($device) => [$device->id => $device->name])->toArray()
$devices->mapWithKeys(fn ($device): array => [$device->id => $device->name])->toArray()
);
return $devices->firstWhere('id', $deviceId);
@ -105,7 +105,7 @@ class MashupCreateCommand extends Command
$playlistId = $this->choice(
'Select a playlist',
$playlists->mapWithKeys(fn (Playlist $playlist) => [$playlist->id => $playlist->name])->toArray()
$playlists->mapWithKeys(fn (Playlist $playlist): array => [$playlist->id => $playlist->name])->toArray()
);
return $playlists->firstWhere('id', $playlistId);
@ -123,13 +123,13 @@ class MashupCreateCommand extends Command
{
$name = $this->ask('Enter a name for this mashup', 'Mashup');
if (mb_strlen($name) < 2) {
if (mb_strlen((string) $name) < 2) {
$this->error('The name must be at least 2 characters.');
return null;
}
if (mb_strlen($name) > 50) {
if (mb_strlen((string) $name) > 50) {
$this->error('The name must not exceed 50 characters.');
return null;
@ -150,7 +150,7 @@ class MashupCreateCommand extends Command
}
$selectedPlugins = collect();
$availablePlugins = $plugins->mapWithKeys(fn ($plugin) => [$plugin->id => $plugin->name])->toArray();
$availablePlugins = $plugins->mapWithKeys(fn ($plugin): array => [$plugin->id => $plugin->name])->toArray();
for ($i = 0; $i < $requiredCount; ++$i) {
$position = match ($i) {

View file

@ -26,7 +26,7 @@ class OidcTestCommand extends Command
/**
* Execute the console command.
*/
public function handle()
public function handle(): int
{
$this->info('Testing OIDC Configuration...');
$this->newLine();

View file

@ -25,7 +25,7 @@ class ScreenGeneratorCommand extends Command
/**
* Execute the console command.
*/
public function handle()
public function handle(): int
{
$deviceId = $this->argument('deviceId');
$view = $this->argument('view');

View file

@ -18,7 +18,7 @@ class CleanupDeviceLogsJob implements ShouldQueue
*/
public function handle(): void
{
Device::each(function ($device) {
Device::each(function ($device): void {
$keepIds = $device->logs()->latest('device_timestamp')->take(50)->pluck('id');
// Delete all other logs for this device

View file

@ -23,7 +23,7 @@ class FetchProxyCloudResponses implements ShouldQueue
*/
public function handle(): void
{
Device::where('proxy_cloud', true)->each(function ($device) {
Device::where('proxy_cloud', true)->each(function ($device): void {
if (! $device->getNextPlaylistItem()) {
try {
$response = Http::withHeaders([

View file

@ -18,12 +18,7 @@ class FirmwareDownloadJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private Firmware $firmware;
public function __construct(Firmware $firmware)
{
$this->firmware = $firmware;
}
public function __construct(private Firmware $firmware) {}
public function handle(): void
{

View file

@ -17,12 +17,7 @@ class FirmwarePollJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private bool $download;
public function __construct(bool $download = false)
{
$this->download = $download;
}
public function __construct(private bool $download = false) {}
public function handle(): void
{

View file

@ -15,8 +15,6 @@ class NotifyDeviceBatteryLowJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct() {}
public function handle(): void
{
$devices = Device::all();
@ -32,9 +30,11 @@ class NotifyDeviceBatteryLowJob implements ShouldQueue
continue;
}
// Skip if battery is not low or notification was already sent
if ($batteryPercent > $batteryThreshold || $device->battery_notification_sent) {
if ($batteryPercent > $batteryThreshold) {
continue;
}
if ($device->battery_notification_sent) {
continue;
}

View file

@ -72,7 +72,7 @@ class Data extends FiltersProvider
*/
public function sample(array $array): mixed
{
if (empty($array)) {
if ($array === []) {
return null;
}

View file

@ -40,15 +40,11 @@ class Numbers extends FiltersProvider
$currency = 'GBP';
}
if ($delimiter === '.' && $separator === ',') {
$locale = 'de';
} else {
$locale = 'en';
}
$locale = $delimiter === '.' && $separator === ',' ? 'de' : 'en';
// 2 decimal places for floats, 0 for integers
$decimal = is_float($value + 0) ? 2 : 0;
return Number::currency($value, in: $currency, precision: $decimal, locale: $locale);
return Number::currency($value, in: $currency, locale: $locale, precision: $decimal);
}
}

View file

@ -35,7 +35,7 @@ class Uniqueness extends FiltersProvider
$randomString = '';
for ($i = 0; $i < $length; ++$i) {
$randomString .= $characters[rand(0, mb_strlen($characters) - 1)];
$randomString .= $characters[random_int(0, mb_strlen($characters) - 1)];
}
return $randomString;

View file

@ -10,14 +10,14 @@ class DeviceAutoJoin extends Component
public bool $isFirstUser = false;
public function mount()
public function mount(): void
{
$this->deviceAutojoin = auth()->user()->assign_new_devices;
$this->isFirstUser = auth()->user()->id === 1;
}
public function updating($name, $value)
public function updating($name, $value): void
{
$this->validate([
'deviceAutojoin' => 'boolean',
@ -30,7 +30,7 @@ class DeviceAutoJoin extends Component
}
}
public function render()
public function render(): \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
{
return view('livewire.actions.device-auto-join');
}

View file

@ -10,7 +10,7 @@ class Logout
/**
* Log the current user out of the application.
*/
public function __invoke()
public function __invoke(): \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
{
Auth::guard('web')->logout();

View file

@ -6,7 +6,7 @@ use Livewire\Component;
class DeviceDashboard extends Component
{
public function render()
public function render(): \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
{
return view('livewire.device-dashboard', ['devices' => auth()->user()->devices()->paginate(10)]);
}

View file

@ -35,7 +35,7 @@ class Device extends Model
'pause_until' => 'datetime',
];
public function getBatteryPercentAttribute()
public function getBatteryPercentAttribute(): int|float
{
$volts = $this->last_battery_voltage;
@ -83,7 +83,7 @@ class Device extends Model
return round($voltage, 2);
}
public function getWifiStrengthAttribute()
public function getWifiStrengthAttribute(): int
{
$rssi = $this->last_rssi_level;
if ($rssi >= 0) {
@ -106,11 +106,7 @@ class Device extends Model
return true;
}
if ($this->proxy_cloud_response && $this->proxy_cloud_response['update_firmware']) {
return true;
}
return false;
return $this->proxy_cloud_response && $this->proxy_cloud_response['update_firmware'];
}
public function getFirmwareUrlAttribute(): ?string
@ -231,7 +227,7 @@ class Device extends Model
return false;
}
$now = $now ? Carbon::instance($now) : now();
$now = $now instanceof DateTimeInterface ? Carbon::instance($now) : now();
// Handle overnight ranges (e.g. 22:00 to 06:00)
return $this->sleep_mode_from < $this->sleep_mode_to
@ -245,7 +241,7 @@ class Device extends Model
return null;
}
$now = $now ? Carbon::instance($now) : now();
$now = $now instanceof DateTimeInterface ? Carbon::instance($now) : now();
$from = $this->sleep_mode_from;
$to = $this->sleep_mode_to;

View file

@ -38,10 +38,8 @@ class Playlist extends Model
}
// Check weekday
if ($this->weekdays !== null) {
if (! in_array(now()->dayOfWeek, $this->weekdays)) {
return false;
}
if ($this->weekdays !== null && ! in_array(now()->dayOfWeek, $this->weekdays)) {
return false;
}
if ($this->active_from !== null && $this->active_until !== null) {
@ -53,10 +51,8 @@ class Playlist extends Model
if ($now >= $this->active_from || $now <= $this->active_until) {
return true;
}
} else {
if ($now >= $this->active_from && $now <= $this->active_until) {
return true;
}
} elseif ($now >= $this->active_from && $now <= $this->active_until) {
return true;
}
return false;

View file

@ -153,9 +153,7 @@ class PlaylistItem extends Model
$plugins = Plugin::whereIn('id', $pluginIds)->get();
// Sort the collection to match plugin_ids order
$plugins = $plugins->sortBy(function ($plugin) use ($pluginIds) {
return array_search($plugin->id, $pluginIds);
})->values();
$plugins = $plugins->sortBy(fn ($plugin): int|string|false => array_search($plugin->id, $pluginIds))->values();
foreach ($plugins as $index => $plugin) {
$size = $this->getLayoutSize($index);

View file

@ -42,7 +42,7 @@ class Plugin extends Model
{
parent::boot();
static::creating(function ($model) {
static::creating(function ($model): void {
if (empty($model->uuid)) {
$model->uuid = Str::uuid();
}
@ -83,7 +83,7 @@ class Plugin extends Model
$currentValue = $this->configuration[$fieldKey] ?? null;
// If the field has a default value and no current value is set, it's not missing
if (($currentValue === null || $currentValue === '' || (is_array($currentValue) && empty($currentValue))) && ! isset($field['default'])) {
if (($currentValue === null || $currentValue === '' || ($currentValue === [])) && ! isset($field['default'])) {
return true; // Found a required field that is not set and has no default
}
}
@ -126,7 +126,7 @@ class Plugin extends Model
// Split URLs by newline and filter out empty lines
$urls = array_filter(
array_map('trim', explode("\n", $this->polling_url)),
fn ($url) => ! empty($url)
fn ($url): bool => ! empty($url)
);
// If only one URL, use the original logic without nesting
@ -237,7 +237,7 @@ class Plugin extends Model
// Converts to: {% assign temp_filtered = collection | filter: "key", "value" %}{% for item in temp_filtered %}
$template = preg_replace_callback(
'/{%\s*for\s+(\w+)\s+in\s+([^|%}]+)\s*\|\s*([^%}]+)%}/',
function ($matches) {
function ($matches): string {
$variableName = mb_trim($matches[1]);
$collection = mb_trim($matches[2]);
$filter = mb_trim($matches[3]);
@ -245,7 +245,7 @@ class Plugin extends Model
return "{% assign {$tempVarName} = {$collection} | {$filter} %}{% for {$variableName} in {$tempVarName} %}";
},
$template
(string) $template
);
return $template;

View file

@ -13,15 +13,10 @@ class BatteryLow extends Notification
{
use Queueable;
private Device $device;
/**
* Create a new notification instance.
*/
public function __construct(Device $device)
{
$this->device = $device;
}
public function __construct(private Device $device) {}
/**
* Get the notification's delivery channels.

View file

@ -11,13 +11,7 @@ use Illuminate\Support\Arr;
class WebhookChannel extends Notification
{
/** @var Client */
protected $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function __construct(protected Client $client) {}
/**
* Send the given notification.

View file

@ -13,13 +13,6 @@ final class WebhookMessage extends Notification
*/
private $query;
/**
* The POST data of the Webhook request.
*
* @var mixed
*/
private $data;
/**
* The headers to send with the request.
*
@ -36,9 +29,8 @@ final class WebhookMessage extends Notification
/**
* @param mixed $data
* @return static
*/
public static function create($data = '')
public static function create($data = ''): self
{
return new self($data);
}
@ -46,10 +38,12 @@ final class WebhookMessage extends Notification
/**
* @param mixed $data
*/
public function __construct($data = '')
{
$this->data = $data;
}
public function __construct(
/**
* The POST data of the Webhook request.
*/
private $data = ''
) {}
/**
* Set the Webhook parameters to be URL encoded.
@ -57,7 +51,7 @@ final class WebhookMessage extends Notification
* @param mixed $query
* @return $this
*/
public function query($query)
public function query($query): self
{
$this->query = $query;
@ -70,7 +64,7 @@ final class WebhookMessage extends Notification
* @param mixed $data
* @return $this
*/
public function data($data)
public function data($data): self
{
$this->data = $data;
@ -84,7 +78,7 @@ final class WebhookMessage extends Notification
* @param string $value
* @return $this
*/
public function header($name, $value)
public function header($name, $value): self
{
$this->headers[$name] = $value;
@ -97,7 +91,7 @@ final class WebhookMessage extends Notification
* @param string $userAgent
* @return $this
*/
public function userAgent($userAgent)
public function userAgent($userAgent): self
{
$this->headers['User-Agent'] = $userAgent;
@ -109,17 +103,14 @@ final class WebhookMessage extends Notification
*
* @return $this
*/
public function verify($value = true)
public function verify($value = true): self
{
$this->verify = $value;
return $this;
}
/**
* @return array
*/
public function toArray()
public function toArray(): array
{
return [
'query' => $this->query,

View file

@ -33,17 +33,19 @@ class AppServiceProvider extends ServiceProvider
$http = clone $this;
$http->server->set('HTTPS', 'off');
if (URL::hasValidSignature($https, $absolute, $ignoreQuery)) {
return true;
}
return URL::hasValidSignature($https, $absolute, $ignoreQuery)
|| URL::hasValidSignature($http, $absolute, $ignoreQuery);
return URL::hasValidSignature($http, $absolute, $ignoreQuery);
});
// Register OIDC provider with Socialite
Socialite::extend('oidc', function ($app) {
$config = $app['config']['services.oidc'] ?? [];
Socialite::extend('oidc', function (\Illuminate\Contracts\Foundation\Application $app): OidcProvider {
$config = $app->make('config')->get('services.oidc', []);
return new OidcProvider(
$app['request'],
$app->make(Request::class),
$config['client_id'] ?? null,
$config['client_secret'] ?? null,
$config['redirect'] ?? null,

View file

@ -233,14 +233,14 @@ class ImageGenerationService
if ($plugin?->id) {
// Check if any devices have custom dimensions or use non-standard DeviceModels
$hasCustomDimensions = Device::query()
->where(function ($query) {
->where(function ($query): void {
$query->where('width', '!=', 800)
->orWhere('height', '!=', 480)
->orWhere('rotate', '!=', 0);
})
->orWhereHas('deviceModel', function ($query) {
->orWhereHas('deviceModel', function ($query): void {
// Only allow caching if all device models have standard dimensions (800x480, rotation=0)
$query->where(function ($subQuery) {
$query->where(function ($subQuery): void {
$subQuery->where('width', '!=', 800)
->orWhere('height', '!=', 480)
->orWhere('rotation', '!=', 0);

View file

@ -33,7 +33,7 @@ class OidcProvider extends AbstractProvider implements ProviderInterface
/**
* Create a new provider instance.
*/
public function __construct($request, $clientId, $clientSecret, $redirectUrl, $scopes = [], $guzzle = [])
public function __construct(\Illuminate\Http\Request $request, $clientId, $clientSecret, $redirectUrl, $scopes = [], $guzzle = [])
{
parent::__construct($request, $clientId, $clientSecret, $redirectUrl, $guzzle);
@ -43,7 +43,7 @@ class OidcProvider extends AbstractProvider implements ProviderInterface
}
// Handle both full well-known URL and base URL
if (str_ends_with($endpoint, '/.well-known/openid-configuration')) {
if (str_ends_with((string) $endpoint, '/.well-known/openid-configuration')) {
$this->baseUrl = str_replace('/.well-known/openid-configuration', '', $endpoint);
} else {
$this->baseUrl = mb_rtrim($endpoint, '/');
@ -73,7 +73,7 @@ class OidcProvider extends AbstractProvider implements ProviderInterface
}
} catch (Exception $e) {
throw new Exception('Failed to load OIDC configuration: '.$e->getMessage());
throw new Exception('Failed to load OIDC configuration: '.$e->getMessage(), $e->getCode(), $e);
}
}

View file

@ -47,44 +47,33 @@ class PluginExportService
$tempDirName = 'temp/'.uniqid('plugin_export_', true);
Storage::makeDirectory($tempDirName);
$tempDir = Storage::path($tempDirName);
try {
// Generate settings.yml content
$settings = $this->generateSettingsYaml($plugin);
$settingsYaml = Yaml::dump($settings, 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
File::put($tempDir.'/settings.yml', $settingsYaml);
// Generate full template content
$fullTemplate = $this->generateFullTemplate($plugin);
$extension = $plugin->markup_language === 'liquid' ? 'liquid' : 'blade.php';
File::put($tempDir.'/full.'.$extension, $fullTemplate);
// Generate shared.liquid if needed (for liquid templates)
if ($plugin->markup_language === 'liquid') {
$sharedTemplate = $this->generateSharedTemplate($plugin);
if ($sharedTemplate) {
File::put($tempDir.'/shared.liquid', $sharedTemplate);
}
// Generate settings.yml content
$settings = $this->generateSettingsYaml($plugin);
$settingsYaml = Yaml::dump($settings, 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
File::put($tempDir.'/settings.yml', $settingsYaml);
// Generate full template content
$fullTemplate = $this->generateFullTemplate($plugin);
$extension = $plugin->markup_language === 'liquid' ? 'liquid' : 'blade.php';
File::put($tempDir.'/full.'.$extension, $fullTemplate);
// Generate shared.liquid if needed (for liquid templates)
if ($plugin->markup_language === 'liquid') {
$sharedTemplate = $this->generateSharedTemplate();
if ($sharedTemplate) {
File::put($tempDir.'/shared.liquid', $sharedTemplate);
}
// Create ZIP file
$zipPath = $tempDir.'/plugin_'.$plugin->trmnlp_id.'.zip';
$zip = new ZipArchive();
if ($zip->open($zipPath, ZipArchive::CREATE) !== true) {
throw new Exception('Could not create ZIP file.');
}
// Add files directly to ZIP root
$this->addDirectoryToZip($zip, $tempDir, '');
$zip->close();
// Return the ZIP file as a download response
return response()->download($zipPath, 'plugin_'.$plugin->trmnlp_id.'.zip');
} catch (Exception $e) {
throw $e;
}
// Create ZIP file
$zipPath = $tempDir.'/plugin_'.$plugin->trmnlp_id.'.zip';
$zip = new ZipArchive();
if ($zip->open($zipPath, ZipArchive::CREATE) !== true) {
throw new Exception('Could not create ZIP file.');
}
// Add files directly to ZIP root
$this->addDirectoryToZip($zip, $tempDir, '');
$zip->close();
// Return the ZIP file as a download response
return response()->download($zipPath, 'plugin_'.$plugin->trmnlp_id.'.zip');
}
/**
@ -150,7 +139,7 @@ class PluginExportService
/**
* Generate the shared template content (for liquid templates)
*/
private function generateSharedTemplate(Plugin $plugin)
private function generateSharedTemplate(): null
{
// For now, we don't have a way to store shared templates separately
// TODO - add support for shared templates
@ -170,14 +159,10 @@ class PluginExportService
foreach ($files as $file) {
if (! $file->isDir()) {
$filePath = $file->getRealPath();
$fileName = basename($filePath);
$fileName = basename((string) $filePath);
// For root directory, just use the filename
if ($zipPath === '') {
$relativePath = $fileName;
} else {
$relativePath = $zipPath.'/'.mb_substr($filePath, mb_strlen($dirPath) + 1);
}
$relativePath = $zipPath === '' ? $fileName : $zipPath.'/'.mb_substr((string) $filePath, mb_strlen($dirPath) + 1);
$zip->addFile($filePath, $relativePath);
}

View file

@ -72,7 +72,7 @@ class PluginImportService
// Check if the file ends with .liquid to set markup language
$markupLanguage = 'blade';
if (pathinfo($filePaths['fullLiquidPath'], PATHINFO_EXTENSION) === 'liquid') {
if (pathinfo((string) $filePaths['fullLiquidPath'], PATHINFO_EXTENSION) === 'liquid') {
$markupLanguage = 'liquid';
}
@ -197,7 +197,7 @@ class PluginImportService
// Check if the file ends with .liquid to set markup language
$markupLanguage = 'blade';
if (pathinfo($filePaths['fullLiquidPath'], PATHINFO_EXTENSION) === 'liquid') {
if (pathinfo((string) $filePaths['fullLiquidPath'], PATHINFO_EXTENSION) === 'liquid') {
$markupLanguage = 'liquid';
}
@ -352,7 +352,7 @@ class PluginImportService
// check if they're in the root of the ZIP or in a subfolder
if ($settingsYamlPath && $fullLiquidPath) {
// If the files are in the root of the ZIP, create a src folder and move them there
$srcDir = dirname($settingsYamlPath);
$srcDir = dirname((string) $settingsYamlPath);
// If the parent directory is not named 'src', create a src directory
if (basename($srcDir) !== 'src') {