diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index d76036d..7d2a805 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -8,14 +8,19 @@ jobs: strategy: fail-fast: false matrix: - php: [8.2, 8.1] - laravel: [10.*, 9.*] + php: ["8.3", "8.2", "8.1"] + laravel: ["^11.0", "^10.0", "^9.0"] dependency-version: [prefer-lowest, prefer-stable] include: - - laravel: 10.* - testbench: 8.* - - laravel: 9.* - testbench: 7.* + - laravel: "^11.0" + testbench: "9.*" + - laravel: "^10.0" + testbench: "8.*" + - laravel: "^9.0" + testbench: "7.*" + exclude: + - laravel: "^11.0" + php: 8.1 name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} diff --git a/CHANGELOG.md b/CHANGELOG.md index a44a81c..d990415 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to `svg-avatar-generator` will be documented in this file. +## 1.4.2 + +- Use laravel validation instead of manually checking configs. +- Added `ConfigValidator` class to define and perform validations. +- Changed modifiers for `$config` and `$extractor` in `SvgAvatarGenerator` class. +- Removed stale exception classes. +- Laravel 11 github workflows. + +## 1.4.1 + +- Laravel 11 support. + ## 1.4.0 - Support for custom fonts. diff --git a/README.md b/README.md index 0195793..9bfbf55 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ Optionally, you can publish the config file with: ```bash php artisan vendor:publish --tag="svg-avatar-generator-config" ``` - -> ⚠️ You should republish the config file after updating. +> [!WARNING] +> You should republish the config file after updating. ## Usage @@ -73,7 +73,8 @@ class User extends Model } ``` -> **Note**: If your accessor is different from the original attribute, you might want to put it in `$appends` array so +> [!NOTE] +> If your accessor is different from the original attribute, you might want to put it in `$appends` array so > that it loads automatically with your model. ### Override default config diff --git a/composer.json b/composer.json index 3f8fcfd..5a27793 100644 --- a/composer.json +++ b/composer.json @@ -24,11 +24,11 @@ "illuminate/contracts": "^9.0 || ^10.0 || ^11.0" }, "require-dev": { - "nunomaduro/collision": "^6.0", - "orchestra/testbench": "^7.0 || ^8.0", - "pestphp/pest": "^1.21", - "pestphp/pest-plugin-laravel": "^1.1", - "phpunit/phpunit": "^9.5", + "nunomaduro/collision": "^6.0 || ^7.0 || ^8.0", + "orchestra/testbench": "^7.0 || ^8.0 || ^9.0", + "pestphp/pest": "^1.21 || ^2.0", + "pestphp/pest-plugin-laravel": "^1.1 || ^2.0", + "phpunit/phpunit": "^9.5 || ^10.1", "spatie/laravel-ray": "^1.32" }, "autoload": { diff --git a/src/Concerns/Tool.php b/src/Concerns/Tool.php index cc70fc2..3b264eb 100644 --- a/src/Concerns/Tool.php +++ b/src/Concerns/Tool.php @@ -3,20 +3,16 @@ namespace Sowren\SvgAvatarGenerator\Concerns; use Arr; -use Sowren\SvgAvatarGenerator\Exceptions\MissingTextException; +use Sowren\SvgAvatarGenerator\Validators\ConfigValidator; trait Tool { /** * Extract initials using configured extractor. - * - * @throws MissingTextException */ protected function extractInitials(): void { - if (! $this->text) { - throw MissingTextException::create(); - } + ConfigValidator::validate('svg_text', $this->text); $initials = $this->extractor->extract($this->text); $this->setInitials($initials); diff --git a/src/Exceptions/InvalidCornerRadius.php b/src/Exceptions/InvalidCornerRadius.php deleted file mode 100644 index 065df0c..0000000 --- a/src/Exceptions/InvalidCornerRadius.php +++ /dev/null @@ -1,11 +0,0 @@ -config = config('svg-avatar'); @@ -122,8 +107,6 @@ public function for(string $text): static /** * Get generated initials. - * - * @throws MissingTextException */ public function getInitials(): string { @@ -155,14 +138,10 @@ public function getSize(): int /** * Set the SVG size between 16 and 512. The generated * SVG is square always. - * - * @throws InvalidSvgSizeException */ public function setSize(int $size): static { - if ($size < 16 || $size > 512) { - throw InvalidSvgSizeException::create($size); - } + ConfigValidator::validate('svg_size', $size); $this->size = $size; @@ -216,14 +195,10 @@ public function getCornerRadius(): int /** * Set corner radius of rectangular shape. - * - * @throws InvalidCornerRadius */ public function setCornerRadius(int $radius): static { - if ($radius < 0 || $radius > 25) { - throw InvalidCornerRadius::create($radius); - } + ConfigValidator::validate('corner_radius', $radius); $this->cornerRadius = $radius; @@ -240,14 +215,10 @@ public function getCustomFontUrl(): ?string /** * Set the custom font url. - * - * @throws InvalidUrlException */ public function setCustomFontUrl(?string $url = null): static { - if (! empty($url) && ! URL::isValidUrl($url)) { - throw InvalidUrlException::create($url); - } + ConfigValidator::validate('custom_font_url', $url); $this->customFontUrl = $url; @@ -282,14 +253,10 @@ public function getFontSize(): int /** * Set font size of the SVG between 10 and 50. - * - * @throws InvalidFontSizeException */ public function setFontSize(int $fontSize): static { - if ($fontSize < 10 || $fontSize > 50) { - throw InvalidFontSizeException::create($fontSize); - } + ConfigValidator::validate('font_size', $fontSize); $this->fontSize = $fontSize; @@ -343,14 +310,10 @@ public function getGradientRotation(): int /** * Set the angle of the color gradient rotation between 0 and 360. - * - * @throws InvalidGradientRotationException */ public function setGradientRotation(int $angle): static { - if ($angle < 0 || $angle > 360) { - throw InvalidGradientRotationException::create($angle); - } + ConfigValidator::validate('gradiant_rotation', $angle); $this->gradientRotation = $angle; @@ -396,14 +359,10 @@ public function getGradientStops(): array /** * Set stop positions of gradients. - * - * @throws InvalidGradientStopException */ public function setGradientStops(int|float ...$offsets): static { - if ((min($offsets) < 0) || max($offsets) > 1) { - throw InvalidGradientStopException::create($offsets); - } + ConfigValidator::validate('gradiant_stops', $offsets); $this->gradientStops = $offsets; @@ -435,13 +394,6 @@ protected function setGradientSet(): static /** * Set default values from config. - * - * @throws InvalidCornerRadius - * @throws InvalidFontSizeException - * @throws InvalidGradientRotationException - * @throws InvalidSvgSizeException - * @throws InvalidGradientStopException - * @throws InvalidUrlException */ protected function build(): void { @@ -461,8 +413,6 @@ protected function build(): void /** * Render the SVG. - * - * @throws MissingTextException */ public function render(): Svg { diff --git a/src/SvgAvatarGeneratorServiceProvider.php b/src/SvgAvatarGeneratorServiceProvider.php index 997fabb..9c07df5 100644 --- a/src/SvgAvatarGeneratorServiceProvider.php +++ b/src/SvgAvatarGeneratorServiceProvider.php @@ -21,13 +21,13 @@ public function configurePackage(Package $package): void ->hasRoute('web'); } - public function bootingPackage() + public function bootingPackage(): void { // We are not going to publish these views $this->loadViewsFrom(__DIR__.'/../resources/views', 'svg'); } - public function registeringPackage() + public function registeringPackage(): void { $this->app->singleton(Extractor::class, fn () => new (config('svg-avatar.extractor'))); } diff --git a/src/Validators/ConfigValidator.php b/src/Validators/ConfigValidator.php new file mode 100644 index 0000000..4ea8750 --- /dev/null +++ b/src/Validators/ConfigValidator.php @@ -0,0 +1,30 @@ + ['int', 'between:0,25'], + 'font_size' => ['int', 'between:10,50'], + 'gradiant_rotation' => ['int', 'between:0,360'], + 'gradiant_stops' => ['array'], + 'gradiant_stops.*' => ['numeric', 'between:0,1'], + 'svg_size' => ['int', 'between:16,512'], + 'custom_font_url' => ['nullable', 'url'], + 'svg_text' => ['required', 'string'], + ]; + + public static function validate(string $key, mixed $value): array + { + $rules = Arr::where(static::$rules, function ($set, $property) use ($key) { + return Str::startsWith($property, $key); + }); + + return Validator::validate([$key => $value], $rules); + } +} diff --git a/tests/ExceptionTest.php b/tests/ExceptionTest.php index a492e27..e4a6776 100644 --- a/tests/ExceptionTest.php +++ b/tests/ExceptionTest.php @@ -1,59 +1,54 @@ 8]); new SvgAvatarGenerator('Rob Stark'); -})->throws(InvalidSvgSizeException::class); +})->throws(ValidationException::class)->expectExceptionMessageMatches('/The svg size(?: field)? must be between 16 and 512/'); it('will throw exception if svg size greater than maximum is provided', function () { config(['svg-avatar.size' => 1024]); new SvgAvatarGenerator('Jon Snow'); -})->throws(InvalidSvgSizeException::class); +})->throws(ValidationException::class)->expectExceptionMessageMatches('/The svg size(?: field)? must be between 16 and 512/'); it('will throw exception if font size less than minimum is provided', function () { config(['svg-avatar.font_size' => 9]); new SvgAvatarGenerator('Sansa Stark'); -})->throws(InvalidFontSizeException::class); +})->throws(ValidationException::class)->expectExceptionMessageMatches('/The font size(?: field)? must be between 10 and 50/'); it('will throw exception if font size greater than maximum is provided', function () { config(['svg-avatar.font_size' => 51]); new SvgAvatarGenerator('Arya Stark'); -})->throws(InvalidFontSizeException::class); +})->throws(ValidationException::class)->expectExceptionMessageMatches('/The font size(?: field)? must be between 10 and 50/'); it('will throw exception if gradient rotation less than minimum is provided', function () { config(['svg-avatar.gradient_rotation' => -1]); new SvgAvatarGenerator('Brandon Stark'); -})->throws(InvalidGradientRotationException::class); +})->throws(ValidationException::class)->expectExceptionMessageMatches('/The gradiant rotation(?: field)? must be between 0 and 360/'); it('will throw exception if gradient rotation greater than maximum is provided', function () { config(['svg-avatar.gradient_rotation' => 361]); new SvgAvatarGenerator('Rickon Stark'); -})->throws(InvalidGradientRotationException::class); +})->throws(ValidationException::class)->expectExceptionMessageMatches('/The gradiant rotation(?: field)? must be between 0 and 360/'); it('will throw missing text exception if text is not set', function () { $generator = new SvgAvatarGenerator(); $generator->getInitials(); -})->throws(MissingTextException::class); +})->throws(ValidationException::class, 'The svg text field is required'); it('will throw exception if gradient stop less than minimum is provided', function () { - config(['svg-avatar.gradient_stops' => [-1, 1]]); + config(['svg-avatar.gradient_stops' => [-1, 0.5]]); new SvgAvatarGenerator('Lyanna Stark'); -})->throws(InvalidGradientStopException::class); +})->throws(ValidationException::class)->expectExceptionMessageMatches('/The gradiant_stops.0(?: field)? must be between 0 and 1/'); it('will throw exception if gradient stop greater than maximum is provided', function () { - config(['svg-avatar.gradient_stops' => [0, 2]]); + config(['svg-avatar.gradient_stops' => [0.2, 2]]); new SvgAvatarGenerator('Benjen Stark'); -})->throws(InvalidGradientStopException::class); +})->throws(ValidationException::class)->expectExceptionMessageMatches('/The gradiant_stops.1(?: field)? must be between 0 and 1/'); it('will throw exception if invalid font url is provided', function () { config(['svg-avatar.custom_font_url' => 'invalid_url']); new SvgAvatarGenerator('Rickard Stark'); -})->throws(InvalidUrlException::class); +})->throws(ValidationException::class)->expectExceptionMessageMatches('/The custom font url(?: field)? must be a valid URL/'); diff --git a/tests/UrlTest.php b/tests/UrlTest.php index 7ec2822..de665a3 100644 --- a/tests/UrlTest.php +++ b/tests/UrlTest.php @@ -1,7 +1,7 @@ throws(MissingTextException::class); +})->throws(ValidationException::class);