diff --git a/composer.json b/composer.json index 7753193..7abd0f6 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "php": "^8.3", "illuminate/contracts": "^11.8.0", "laravel/framework": "^v11.0.0", + "laravel/prompts": "^0.1.25", "league/iso3166": "^4.3", "spatie/laravel-data": "^4.5", "spatie/laravel-package-tools": "^1.16", diff --git a/composer.lock b/composer.lock index 501bd72..b2fa7fa 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "14158bcf0d818fbc2b1e37ee7719829a", + "content-hash": "f0fe05696047c8a0bf1a720013ec0cab", "packages": [ { "name": "amphp/amp", diff --git a/src/Casts/FloatScaleCast.php b/src/Casts/FloatScaleCast.php new file mode 100644 index 0000000..fa794a0 --- /dev/null +++ b/src/Casts/FloatScaleCast.php @@ -0,0 +1,49 @@ + + */ +final class FloatScaleCast implements CastsAttributes +{ + /** + * Cast the given value. + * + * @param array $attributes + * + * @throws MathException + * @throws RoundingNecessaryException + */ + public function get(Model $model, string $key, mixed $value, array $attributes): ?float + { + if ($value === null) { + return null; + } + + //@phpstan-ignore-next-line + return math($value)->ensureScale()->toFloat(); + } + + /** + * Prepare the given value for storage. + * + * @param array $attributes + * + * @throws MathException + * @throws RoundingNecessaryException + */ + public function set(Model $model, string $key, mixed $value, array $attributes): ?string + { + if ($value === null) { + return null; + } + + return math($value)->ensureScale()->toString(); + } +} diff --git a/src/Commands/HorizonWipeCommand.php b/src/Commands/HorizonWipeCommand.php new file mode 100644 index 0000000..9ba7701 --- /dev/null +++ b/src/Commands/HorizonWipeCommand.php @@ -0,0 +1,36 @@ +del('horizon:failed:*'); + Redis::connection()->del('horizon:failed_jobs'); + //@phpstan-ignore-next-line + Redis::connection(name: 'horizon')->client()->flushAll(); + Artisan::call('horizon:clear'); + Artisan::call('horizon:clear-metrics'); + Artisan::call('horizon:purge'); + Artisan::call('queue:flush'); + + return self::SUCCESS; + } +} diff --git a/src/Concerns/HasBooleanStates.php b/src/Concerns/HasBooleanStates.php new file mode 100644 index 0000000..bc0f99a --- /dev/null +++ b/src/Concerns/HasBooleanStates.php @@ -0,0 +1,48 @@ +success = true; + + return $this; + } + + /** + * Mark the process as failed + */ + public function setAsFailed(): static + { + $this->success = false; + + return $this; + } + + /** + * Check if it was successful + */ + public function ok(): bool + { + return $this->success; + } + + /** + * Check if it was failed + */ + public function failed(): bool + { + return ! $this->success; + } +} diff --git a/src/Concerns/HasDataPropertiesReflection.php b/src/Concerns/HasDataPropertiesReflection.php new file mode 100644 index 0000000..85fb7f1 --- /dev/null +++ b/src/Concerns/HasDataPropertiesReflection.php @@ -0,0 +1,66 @@ + + */ + public static function getParams(array $only = [], array $except = []): Collection + { + $class = static::class; + + return collect(self::$paramCache[$class] ??= self::resolveParams()) + ->when(! empty($only), fn ($params) => $params->filter(fn ($param) => in_array($param, $only))) + ->when(! empty($except), fn ($params) => $params->reject(fn ($param) => in_array($param, $except))) + ->values(); + } + + /** + * Get the params prefixed + * + * @param string[] $only + * @param string[] $except + * @return Collection + */ + public static function getParamsPrefixed(string $prefix, array $only = [], array $except = []): Collection + { + return collect(self::getParams()) + ->when(! empty($only), fn ($params) => $params->filter(fn ($param) => in_array($param, $only))) + ->when(! empty($except), fn ($params) => $params->reject(fn ($param) => in_array($param, $except))) + ->map(fn (string $param) => "$prefix.$param") + ->values(); + } + + /** + * Get the function params prefixed + * + * @return array + */ + private static function resolveParams(): array + { + /** @var ReflectionClass $reflection */ + $reflection = new ReflectionClass(static::class); + $constructor = $reflection->getConstructor(); + + return $constructor + ? array_map(fn ($param) => $param->getName(), $constructor->getParameters()) + : []; + } + + /** + * Ensure we clear the cache on destruct + */ + public function __destruct() + { + unset(self::$paramCache[static::class]); + } +} diff --git a/src/Concerns/HasQueryTimeScopes.php b/src/Concerns/HasQueryTimeScopes.php new file mode 100644 index 0000000..3d602f7 --- /dev/null +++ b/src/Concerns/HasQueryTimeScopes.php @@ -0,0 +1,76 @@ +where($column, '>=', $start); + } + + if ($end !== null) { + $this->where($column, '<=', $end); + } + + return $this; + } + + public function whereIsNewerThanDays(float|int $days, string $column = 'created_at'): static + { + if ($days > 0) { + return $this->where($column, '>=', now()->subDays($days)); + } + + return $this; + } + + public function whereIsOlderThanDays(float|int $days, string $column = 'created_at'): static + { + if ($days > 0) { + return $this->where($column, '<=', now()->subDays($days)); + } + + return $this; + } + + public function whereInLastMonths(int $months = 1, string $column = 'created_at'): static + { + return $this->where($column, '>=', now()->subMonths($months)); + } + + public function whereInLastDays(int $days = 1, string $column = 'created_at'): static + { + return $this->where($column, '>=', now()->subDays($days)); + } + + public function whereInLastWeek(string $column = 'created_at'): static + { + return $this->where($column, '>=', now()->subWeek()); + } + + public function whereLastHours(float|int $hours = 1, string $column = 'created_at'): static + { + return $this->where($column, '>=', now()->subHours($hours)); + } + + public function whereCreatedInLast24Hours(): static + { + return $this->whereLastHours(24); + } + + public function whereCreatedInLast48Hours(): static + { + return $this->whereLastHours(48); + } +} diff --git a/src/Helpers/generic.php b/src/Helpers/generic.php index 610efb7..2bd992b 100644 --- a/src/Helpers/generic.php +++ b/src/Helpers/generic.php @@ -1,8 +1,13 @@ withHeaders([ + 'sec-ch-ua-platform' => '"macOS"', + 'sec-ch-ua-mobile' => '?0', + 'sec-ch-ua' => '"Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"', + ]) + ->throw(fn () => throw new Exception('Could not download file')) + ->sink($path) + ->get($url); + + return new UploadedFile($path, $filename); + } +} + +if (! function_exists('math')) { + + /** + * Helper to quickly create a math object based on the project config. + */ + function math(float|int|string|BigDecimal $number): Math + { + return Math::of( + $number, + Config::integer('app.decimal_scale', Config::integer('laravel-helpers.math.decimal_scale', 10)), + Config::integer('app.decimal_integer', Config::integer('laravel-helpers.math.decimal_integer', 10)), + ); } } diff --git a/src/LaravelHelpersServiceProvider.php b/src/LaravelHelpersServiceProvider.php index 8bf7531..bd7fc3f 100644 --- a/src/LaravelHelpersServiceProvider.php +++ b/src/LaravelHelpersServiceProvider.php @@ -11,7 +11,10 @@ public function configurePackage(Package $package): void { $package ->name('helpers') - ->hasConfigFile('laravel-helpers'); + ->hasConfigFile('laravel-helpers') + ->hasCommands([ + Commands\HorizonWipeCommand::class, + ]); } public function bootingPackage(): void diff --git a/src/Macros/InertiaMacros.php b/src/Macros/InertiaMacros.php deleted file mode 100644 index 4c5116e..0000000 --- a/src/Macros/InertiaMacros.php +++ /dev/null @@ -1,43 +0,0 @@ -shared($key, []); - // We need to evaluate the close for resolving & merge the values - if ($sharedValue instanceof Closure) { - $sharedValue = $sharedValue(); - } - // @phpstan-ignore-next-line - $this->share( - $key, - array_merge_recursive($sharedValue, [$value]) - ); - - // @phpstan-ignore-next-line - return $this; - }); - } - } -} diff --git a/src/Macros/StrMacros.php b/src/Macros/StrMacros.php index d0ead16..acd5a90 100644 --- a/src/Macros/StrMacros.php +++ b/src/Macros/StrMacros.php @@ -40,17 +40,17 @@ public static function username(): void return $string; } - $parsed = Str::slug($string); + $parsed = Str::slug($parsed); $counter = 1; $username = $parsed; /** * @var Authenticatable|Model $model */ - $model = config('auth.providers.users.model', config('auth.model', 'App\User')); + $model = config('auth.providers.users.model', config('auth.model', 'App\Models\User')); // @phpstan-ignore-next-line while ($model::query()->where('username', $username)->exists()) { - $username = $parsed.$counter; + $username = $parsed.($counter > 1 ? $counter : ''); $counter++; }