Skip to content

Commit

Permalink
Merge pull request #7 from sowrensen/dev
Browse files Browse the repository at this point in the history
Support for custom extractor
  • Loading branch information
sowrensen authored Mar 14, 2023
2 parents 20d8c62 + 994db83 commit 5ae3668
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 44 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ phpstan.neon
testbench.yaml
vendor
node_modules
.DS_Store
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

All notable changes to `svg-avatar-generator` will be documented in this file.

## 1.2.0

- Support for custom extractor.
- New key `extractor` in **svg-avatar** config.

## 1.1.0

- Support for setting multiple sets of gradient colors.
Expand Down
35 changes: 31 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/sowrensen/svg-avatar-generator/run-tests.yml?branch=main&label=Tests)](https://github.com/sowrensen/svg-avatar-generator/actions?query=workflow%3ATests+branch%3Amain)
[![Total Downloads](https://img.shields.io/packagist/dt/sowrensen/svg-avatar-generator.svg)](https://packagist.org/packages/sowrensen/svg-avatar-generator)

Generating SVG avatars on the fly is nothing new. There are a lot of free/paid services and packages to do that. So why
Generating SVG avatars on the fly is nothing new. There are tons of free/paid services and packages available to do that. So, why
another package for same task?

Well, this package has some subtle advantages over available packages, here's a few of them:
Well, this one has some subtle but nifty advantages over available packages, here's a few of them:

- [x] No external api call is required. 🤝🏼
- [x] No external api call is required, it's totally offline. 🛰️
- [x] Unlike some other available options, doesn't require heavy-weight image processing libraries like **Intervention**.
🧺
- [x] Doesn't have any binary dependency, so nothing needs to be installed on server. 🗃️
- [x] Supports gradient background. 🦜
- [x] Supports random gradients based on defined presets in config. 🦚
- [x] Ability to customize initials. ✍🏼
- [x] Ability to customize initials and extractor. ✍🏼

## Requirements

Expand Down Expand Up @@ -106,6 +106,33 @@ You can define the second initial using studly case. For example,
| Johndoe | JO |
| JohndoE | JE |

### Customize Extractor

The default initial extractor class produces results shown above. However, if you want something different, you can create your own Extractor class. To do so create a new class that implements `Sowren\SvgAvatarGenerator\Extractors\Extractor` interface. An ideal place to put this class would be under `App\Extractors` namespace in your app directory.

```php
<?php

namespace App\Extractors;

use Sowren\SvgAvatarGenerator\Extractors\Extractor;

class CustomExtractor implements Extractor
{
public function extract(string $text): string
{
// Write your custom logic and return initials
}
}
```

After doing that, set the class as default extractor in config.

```php
// ...
'extractor' => App\Extractors\CustomExtractor::class,
```

## Sample Output

<img src="https://user-images.githubusercontent.com/13097375/221879852-b8283a4a-f3ff-42a9-b37a-07cbc9bd0afe.png" height="128"/>
Expand Down
27 changes: 27 additions & 0 deletions config/svg-avatar.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,33 @@
*/
'gradient_rotation' => 120,

/*
|--------------------------------------------------------------------------
| Extractor
|--------------------------------------------------------------------------
|
| Extractor is responsible for taking initials out of the passed
| string. The default extractor is pretty smart, if only one
| word is given, it will look for second capital character
| in the word, else the consecutive second character
| will be taken.
|
| Examples:
| - 'John Doe' will produce 'JD'
| - 'JohnDoe' will produce 'JD'
| - 'Johndoe' will produce 'JO'
| - 'JohndoE' will produce 'JE'
|
| However if you want to write your own extractor, you should create a class
| that implements Sowren\SvgAvatarGenerator\Extractors\Extractor interface
| and set it up here.
|
| Type: Sowren\SvgAvatarGenerator\Extractors\Extractor
| Default: Sowren\SvgAvatarGenerator\Extractors\DefaultExtractor::class
|
*/
'extractor' => Sowren\SvgAvatarGenerator\Extractors\DefaultExtractor::class,

/*
|--------------------------------------------------------------------------
| SVG URL
Expand Down
31 changes: 4 additions & 27 deletions src/Concerns/Tool.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,23 @@
namespace Sowren\SvgAvatarGenerator\Concerns;

use Arr;
use Exception;
use Sowren\SvgAvatarGenerator\Exceptions\MissingTextException;
use Str;

trait Tool
{
/**
* Extract initials from given text/name. If only one word is given,
* it will look for second capital character in the word, else
* the consecutive second character will be taken.
* Extract initials using configured extractor.
*
* @throws MissingTextException
*/
protected function extractInitials(): void
{
$name = $this->text;

if (Str::contains($name, ' ')) {
// If name has more than one part then break each part upto each space
$parts = Str::of($name)->explode(' ');
} else {
// If name has only one part then try to find out if there are
// any uppercase letters in the string. Then break the string
// upto each uppercase letters, this allows to pass names in
// studly case, e.g. 'SowrenSen'. If no uppercase letter is
// found, $parts will have only one item in the array.
$parts = Str::of($name)->kebab()->replace('-', ' ')->explode(' ');
}

try {
$firstInitial = $parts->first()[0];

// If only one part is found, take the second letter as second
// initial, else take the first letter of the last part.
$secondInitial = ($parts->count() === 1) ? $parts->first()[1] : $parts->last()[0];
} catch (Exception) {
if (! $this->text) {
throw MissingTextException::create();
}

$this->setInitials(strtoupper($firstInitial.$secondInitial));
$initials = $this->extractor->extract($this->text);
$this->setInitials($initials);
}

/**
Expand Down
36 changes: 36 additions & 0 deletions src/Extractors/DefaultExtractor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Sowren\SvgAvatarGenerator\Extractors;

use Str;

class DefaultExtractor implements Extractor
{
/**
* Extract initials from given text/name. If only one word is given,
* it will look for second capital character in the word, else
* the consecutive second character will be taken.
*/
public function extract(string $text): string
{
if (Str::contains($text, ' ')) {
// If name has more than one part then break each part upto each space
$parts = Str::of($text)->explode(' ');
} else {
// If name has only one part then try to find out if there are
// any uppercase letters in the string. Then break the string
// upto each uppercase letters, this allows to pass names in
// studly case, e.g. 'SowrenSen'. If no uppercase letter is
// found, $parts will have only one item in the array.
$parts = Str::of($text)->kebab()->replace('-', ' ')->explode(' ');
}

$firstInitial = $parts->first()[0];

// If only one part is found, take the second letter as second
// initial, else take the first letter of the last part.
$secondInitial = ($parts->count() === 1) ? $parts->first()[1] : $parts->last()[0];

return strtoupper($firstInitial.$secondInitial);
}
}
11 changes: 11 additions & 0 deletions src/Extractors/Extractor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Sowren\SvgAvatarGenerator\Extractors;

interface Extractor
{
/**
* Extract initials from given text.
*/
public function extract(string $text): string;
}
21 changes: 8 additions & 13 deletions src/SvgAvatarGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Sowren\SvgAvatarGenerator\Exceptions\InvalidGradientStopException;
use Sowren\SvgAvatarGenerator\Exceptions\InvalidSvgSizeException;
use Sowren\SvgAvatarGenerator\Exceptions\MissingTextException;
use Sowren\SvgAvatarGenerator\Extractors\Extractor;

class SvgAvatarGenerator
{
Expand Down Expand Up @@ -71,6 +72,11 @@ class SvgAvatarGenerator
*/
private array $config;

/**
* Instance of predefined extractor.
*/
public Extractor $extractor;

/**
* @throws InvalidSvgSizeException
* @throws InvalidFontSizeException
Expand All @@ -80,23 +86,12 @@ class SvgAvatarGenerator
public function __construct(public ?string $text = null)
{
$this->config = config('svg-avatar');
$this->extractor = app(Extractor::class);
$this->build();
}

/**
* Set the text or name to be used in the SVG. If only one word
* is given, it will look for second capital character in the
* word, else the consecutive second character will be taken.
*
* Examples:
*
* 'John Doe' will produce 'JD'
*
* 'JohnDoe' will produce 'JD'
*
* 'Johndoe' will produce 'JO'
*
* 'JohndoE' will produce 'JE'
* Set the text or name to be used in the SVG.
*/
public function for(string $text): static
{
Expand Down
6 changes: 6 additions & 0 deletions src/SvgAvatarGeneratorServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Sowren\SvgAvatarGenerator;

use Sowren\SvgAvatarGenerator\Extractors\Extractor;
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;

Expand All @@ -25,4 +26,9 @@ public function bootingPackage()
// We are not going to publish these views
$this->loadViewsFrom(__DIR__.'/../resources/views', 'svg');
}

public function registeringPackage()
{
$this->app->singleton(Extractor::class, fn () => new (config('svg-avatar.extractor')));
}
}
File renamed without changes.

0 comments on commit 5ae3668

Please sign in to comment.