├── .github
├── dependabot.yml
└── workflows
│ ├── pint.yml
│ └── run-tests.yml
├── .gitignore
├── .styleci.yml
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── composer.json
├── config
└── config.php
├── phpunit.xml.dist
├── resources
└── views
│ └── img.blade.php
├── src
├── Unavatar.php
├── UnavatarServiceProvider.php
└── View
│ └── Components
│ └── Img.php
└── tests
├── ComponentTest.php
├── TestCase.php
└── UnavatarTest.php
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: composer
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | open-pull-requests-limit: 10
8 |
--------------------------------------------------------------------------------
/.github/workflows/pint.yml:
--------------------------------------------------------------------------------
1 | name: pint
2 |
3 | on:
4 | push:
5 | pull_request:
6 |
7 | jobs:
8 | phpcs:
9 | runs-on: ubuntu-latest
10 | timeout-minutes: 5
11 | steps:
12 | - uses: actions/checkout@v4
13 | - uses: shivammathur/setup-php@v2
14 | with:
15 | php-version: 8.2
16 | - run: composer install --no-interaction --no-scripts
17 | - run: vendor/bin/pint --test
18 |
--------------------------------------------------------------------------------
/.github/workflows/run-tests.yml:
--------------------------------------------------------------------------------
1 | name: run-tests
2 |
3 | on:
4 | pull_request:
5 | push:
6 |
7 | jobs:
8 | test:
9 | runs-on: ubuntu-latest
10 |
11 | strategy:
12 | fail-fast: false
13 | matrix:
14 | php: ['8.3', '8.2', '8.1', '8.0']
15 | laravel: ['11.*', '10.*', '9.*', '8.*']
16 | dependency-version: ['prefer-lowest', 'prefer-stable']
17 | exclude:
18 | - laravel: '11.*'
19 | php: '8.1'
20 | - laravel: '11.*'
21 | php: '8.0'
22 | - laravel: '10.*'
23 | php: '8.0'
24 | - laravel: '9.*'
25 | dependency-version: 'prefer-lowest'
26 | - laravel: '8.*'
27 | dependency-version: 'prefer-lowest'
28 |
29 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }}
30 |
31 | steps:
32 | - uses: actions/checkout@v2
33 |
34 | - uses: shivammathur/setup-php@v2
35 | with:
36 | php-version: ${{ matrix.php }}
37 | extensions: dom, curl, libxml, mbstring, zip
38 |
39 | - name: Install dependencies
40 | run: |
41 | composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update
42 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest
43 |
44 | - run: vendor/bin/phpunit
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | /coverage/
3 | /composer.lock
4 | /phpunit.xml
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: laravel
2 |
3 | risky: true
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to `laravel-unavatar` will be documented in this file
4 |
5 | ## 0.5.0 - 2024-06-25
6 |
7 | - drop PHP7.4 support
8 | - add Laravel 10 & 11 support
9 | - drop `astrotomic/php-unavatar` v0.2 support
10 |
11 | ## 0.4.0 - 2023-08-09
12 |
13 | - add `astrotomic/php-unavatar` v0.3 support
14 |
15 | ## 0.3.0 - 2022-04-08
16 |
17 | - add Laravel 9 support
18 |
19 | ## 0.2.1 - 2020-12-20
20 |
21 | - fix namespace
22 |
23 | ## 0.2.0 - 2020-12-20
24 |
25 | - add Laravel 8 support
26 | - add PHP 8 support
27 | - add Blade component ``
28 | - drop Laravel 6 & 7 support
29 |
30 | ## 0.1.1 - 2020-03-12
31 |
32 | - add Laravel 7 support
33 |
34 | ## 0.1.0 - 2020-02-22
35 |
36 | - initial release
37 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Astrotomic
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Laravel Unavatar
2 |
3 | [](https://packagist.org/packages/astrotomic/laravel-unavatar)
4 | [](https://github.com/Astrotomic/laravel-unavatar/blob/master/LICENSE)
5 | [](https://plant.treeware.earth/Astrotomic/laravel-unavatar)
6 | [](https://www.larabelles.com/)
7 |
8 | [](https://github.com/Astrotomic/laravel-unavatar/actions?query=workflow%3Arun-tests)
9 | [](https://styleci.io/repos/242217544)
10 | [](https://packagist.org/packages/astrotomic/laravel-unavatar)
11 |
12 | This package provides a Laravel wrapper for [unavatar](https://unavatar.now.sh).
13 |
14 | ## Installation
15 |
16 | You can install the package via composer:
17 |
18 | ```bash
19 | composer require astrotomic/laravel-unavatar
20 | php artisan vendor:publish --provider="Astrotomic\LaravelUnavatar\UnavatarServiceProvider" --tag=config
21 | ```
22 |
23 | ## Usage
24 |
25 | Most of the logic and possibilities is inherited from the [astrotomic/php-unavatar](https://github.com/Astrotomic/php-unavatar) base package.
26 | On top this package adds some Laravel specific possibilities.
27 | The `\Astrotomic\LaravelUnavatar\Unavatar` class implements several interfaces:
28 |
29 | - `\Illuminate\Contracts\Support\Renderable`
30 | - `\Illuminate\Contracts\Support\Responsable`
31 | - `\Illuminate\Contracts\Support\Htmlable`
32 | - `\Illuminate\Contracts\Support\Jsonable`
33 | - `\JsonSerializable`
34 | - `\Illuminate\Contracts\Support\Arrayable`
35 |
36 | So you can use the use your `Unavatar` instances in your controllers as response but for sure also in your views.
37 | The last three ones will use the [unavatar](https://unavatar.now.sh) JSON API - so they will start a HTTP request.
38 |
39 | ### Blade Component
40 |
41 | The package provides a blade component you can use in your views.
42 |
43 | ```html
44 |
45 |
46 |
51 | ```
52 |
53 | You can also publish the used view and customize it.
54 |
55 | ### Testing
56 |
57 | ```bash
58 | composer test
59 | ```
60 |
61 | ### Changelog
62 |
63 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.
64 |
65 | ## Contributing
66 |
67 | Please see [CONTRIBUTING](https://github.com/Astrotomic/.github/blob/master/CONTRIBUTING.md) for details. You could also be interested in [CODE OF CONDUCT](https://github.com/Astrotomic/.github/blob/master/CODE_OF_CONDUCT.md).
68 |
69 | ### Security
70 |
71 | If you discover any security related issues, please check [SECURITY](https://github.com/Astrotomic/.github/blob/master/SECURITY.md) for steps to report it.
72 |
73 | ## Credits
74 |
75 | - [Tom Witkowski](https://github.com/Gummibeer)
76 | - [All Contributors](../../contributors)
77 |
78 | ## License
79 |
80 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
81 |
82 | ## Treeware
83 |
84 | You're free to use this package, but if it makes it to your production environment I would highly appreciate you buying the world a tree.
85 |
86 | It’s now common knowledge that one of the best tools to tackle the climate crisis and keep our temperatures from rising above 1.5C is to [plant trees](https://www.bbc.co.uk/news/science-environment-48870920). If you contribute to my forest you’ll be creating employment for local families and restoring wildlife habitats.
87 |
88 | You can buy trees at [offset.earth/treeware](https://plant.treeware.earth/Astrotomic/laravel-unavatar)
89 |
90 | Read more about Treeware at [treeware.earth](https://treeware.earth)
91 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "astrotomic/laravel-unavatar",
3 | "description": "Laravel integration of unavatar service.",
4 | "license": "MIT",
5 | "type": "library",
6 | "keywords": [
7 | "astrotomic",
8 | "laravel-unavatar",
9 | "laravel",
10 | "unavatar",
11 | "avatar"
12 | ],
13 | "authors": [
14 | {
15 | "name": "Tom Witkowski",
16 | "email": "gummibeer@astrotomic.info",
17 | "homepage": "https://gummibeer.de",
18 | "role": "Developer"
19 | }
20 | ],
21 | "homepage": "https://astrotomic.info",
22 | "support": {
23 | "email": "dev@astrotomic.info",
24 | "issues": "https://github.com/Astrotomic/laravel-unavatar/issues",
25 | "source": "https://github.com/Astrotomic/laravel-unavatar"
26 | },
27 | "require": {
28 | "php": "^8.0",
29 | "ext-json": "*",
30 | "astrotomic/php-unavatar": "^0.3.0",
31 | "illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0",
32 | "illuminate/view": "^8.0 || ^9.0 || ^10.0 || ^11.0"
33 | },
34 | "require-dev": {
35 | "gajus/dindent": "^2.0",
36 | "laravel/pint": "^1.0",
37 | "orchestra/testbench": "^6.0 || ^7.0 || ^8.0 || ^9.0",
38 | "phpunit/phpunit": "^9.3 || ^10.0"
39 | },
40 | "autoload": {
41 | "psr-4": {
42 | "Astrotomic\\Unavatar\\Laravel\\": "src"
43 | }
44 | },
45 | "autoload-dev": {
46 | "psr-4": {
47 | "Astrotomic\\Unavatar\\Laravel\\Tests\\": "tests"
48 | }
49 | },
50 | "config": {
51 | "sort-packages": true
52 | },
53 | "extra": {
54 | "composer-normalize": {
55 | "indent-size": 4,
56 | "indent-style": "space"
57 | },
58 | "laravel": {
59 | "providers": [
60 | "Astrotomic\\Unavatar\\Laravel\\UnavatarServiceProvider"
61 | ]
62 | }
63 | },
64 | "scripts": {
65 | "fix": "@php vendor/bin/pint",
66 | "test": "vendor/bin/phpunit",
67 | "test-coverage": "vendor/bin/phpunit --coverage-html coverage"
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/config/config.php:
--------------------------------------------------------------------------------
1 | null,
8 | ];
9 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 | tests
17 |
18 |
19 |
20 |
21 | src/
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/resources/views/img.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
14 |
15 |
merge(['alt' => "{$identifier} avatar", 'loading' => 'lazy']) }}
18 | />
--------------------------------------------------------------------------------
/src/Unavatar.php:
--------------------------------------------------------------------------------
1 | fallback = config('unavatar.fallback');
29 | }
30 |
31 | public function render(): string
32 | {
33 | return $this->toHtml();
34 | }
35 |
36 | public function toHtml(): string
37 | {
38 | return $this->toImg();
39 | }
40 |
41 | public function toResponse($request): Response
42 | {
43 | if ($request->expectsJson()) {
44 | return new JsonResponse($this->toArray());
45 | }
46 |
47 | return new RedirectResponse($this->toUrl(), 302);
48 | }
49 |
50 | public function toJson($options = 0): string
51 | {
52 | return json_encode($this->jsonSerialize(), $options);
53 | }
54 |
55 | public function jsonSerialize(): array
56 | {
57 | return $this->toArray();
58 | }
59 |
60 | public function toArray(): array
61 | {
62 | $url = $this->toUrl();
63 |
64 | $url .= Str::contains($url, '?')
65 | ? '&json'
66 | : '?json';
67 |
68 | return json_decode(file_get_contents($url), true);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/UnavatarServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->runningInConsole()) {
13 | $this->publishes([
14 | __DIR__.'/../config/config.php' => config_path('unavatar.php'),
15 | ], 'config');
16 |
17 | $this->publishes([
18 | __DIR__.'/../resources/views' => resource_path('views/vendor/unavatar'),
19 | ], 'views');
20 | }
21 |
22 | $this->loadViewsFrom(__DIR__.'/../resources/views', 'unavatar');
23 |
24 | Blade::componentNamespace('Astrotomic\Unavatar\Laravel\View\Components', 'unavatar');
25 | }
26 |
27 | public function register(): void
28 | {
29 | $this->mergeConfigFrom(__DIR__.'/../config/config.php', 'unavatar');
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/View/Components/Img.php:
--------------------------------------------------------------------------------
1 | identifier = $clearbit;
39 | $this->provider = BaseUnavatar::PROVIDER_CLEARBIT;
40 | }
41 |
42 | if ($deviantart) {
43 | $this->identifier = $deviantart;
44 | $this->provider = BaseUnavatar::PROVIDER_DEVIANTART;
45 | }
46 |
47 | if ($dribbble) {
48 | $this->identifier = $dribbble;
49 | $this->provider = BaseUnavatar::PROVIDER_DRIBBBLE;
50 | }
51 |
52 | if ($duckduckgo) {
53 | $this->identifier = $duckduckgo;
54 | $this->provider = BaseUnavatar::PROVIDER_DUCKDUCKGO;
55 | }
56 | if ($facebook) {
57 | $this->identifier = $facebook;
58 | $this->provider = BaseUnavatar::PROVIDER_FACEBOOK;
59 | }
60 |
61 | if ($github) {
62 | $this->identifier = $github;
63 | $this->provider = BaseUnavatar::PROVIDER_GITHUB;
64 | }
65 |
66 | if ($gravatar) {
67 | $this->identifier = $gravatar;
68 | $this->provider = BaseUnavatar::PROVIDER_GRAVATAR;
69 | }
70 |
71 | if ($instagram) {
72 | $this->identifier = $instagram;
73 | $this->provider = BaseUnavatar::PROVIDER_INSTAGRAM;
74 | }
75 |
76 | if ($soundcloud) {
77 | $this->identifier = $soundcloud;
78 | $this->provider = BaseUnavatar::PROVIDER_SOUNDCLOUD;
79 | }
80 |
81 | if ($substack) {
82 | $this->identifier = $substack;
83 | $this->provider = BaseUnavatar::PROVIDER_SUBSTACK;
84 | }
85 |
86 | if ($telegram) {
87 | $this->identifier = $telegram;
88 | $this->provider = BaseUnavatar::PROVIDER_TELEGRAM;
89 | }
90 |
91 | if ($twitter) {
92 | $this->identifier = $twitter;
93 | $this->provider = BaseUnavatar::PROVIDER_TWITTER;
94 | }
95 |
96 | if ($youtube) {
97 | $this->identifier = $youtube;
98 | $this->provider = BaseUnavatar::PROVIDER_YOUTUBE;
99 | }
100 |
101 | $this->identifier ??= $username ?? $email ?? $domain;
102 | $this->fallback = $fallback;
103 | }
104 |
105 | public function render(): View
106 | {
107 | return view('unavatar::img');
108 | }
109 |
110 | public function url(): string
111 | {
112 | $unavatar = LaravelUnavatar::make($this->identifier, $this->provider);
113 |
114 | if ($this->fallback) {
115 | $unavatar->fallback($this->fallback);
116 | }
117 |
118 | return $unavatar->toUrl();
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/tests/ComponentTest.php:
--------------------------------------------------------------------------------
1 |
16 | HTML;
17 |
18 | $this->assertComponentRenders($expected, '');
19 | }
20 |
21 | /** @test */
22 | public function it_can_render_with_fallback(): void
23 | {
24 | $expected = <<<'HTML'
25 |
30 | HTML;
31 |
32 | $this->assertComponentRenders($expected, '');
33 | }
34 |
35 | /** @test */
36 | public function it_can_render_clearbit(): void
37 | {
38 | $expected = <<<'HTML'
39 |
44 | HTML;
45 |
46 | $this->assertComponentRenders($expected, '');
47 | }
48 |
49 | /** @test */
50 | public function it_can_render_deviantart(): void
51 | {
52 | $expected = <<<'HTML'
53 |
58 | HTML;
59 |
60 | $this->assertComponentRenders($expected, '');
61 | }
62 |
63 | /** @test */
64 | public function it_can_render_dribbble(): void
65 | {
66 | $expected = <<<'HTML'
67 |
72 | HTML;
73 |
74 | $this->assertComponentRenders($expected, '');
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | blade($template, $data);
25 |
26 | $this->assertSame(
27 | $indenter->indent($expected),
28 | $indenter->indent($blade)
29 | );
30 | }
31 |
32 | protected function blade(string $template, array $data = []): string
33 | {
34 | $tempDirectory = sys_get_temp_dir();
35 |
36 | if (! in_array($tempDirectory, ViewFacade::getFinder()->getPaths())) {
37 | ViewFacade::addLocation(sys_get_temp_dir());
38 | }
39 |
40 | $tempFile = tempnam($tempDirectory, 'laravel-blade').'.blade.php';
41 |
42 | file_put_contents($tempFile, $template);
43 |
44 | return view(Str::before(basename($tempFile), '.blade.php'), $data);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/tests/UnavatarTest.php:
--------------------------------------------------------------------------------
1 | ', $unavatar->render());
24 | }
25 |
26 | /** @test */
27 | public function it_is_htmlable(): void
28 | {
29 | $unavatar = Unavatar::github('Gummibeer');
30 |
31 | self::assertArrayHasKey(Htmlable::class, class_implements($unavatar));
32 | self::assertSame('
', $unavatar->toHtml());
33 | }
34 |
35 | /** @test */
36 | public function it_is_responsable_redirect(): void
37 | {
38 | $unavatar = Unavatar::github('Gummibeer');
39 |
40 | self::assertArrayHasKey(Responsable::class, class_implements($unavatar));
41 |
42 | $redirect = $unavatar->toResponse(Request::createFromGlobals());
43 |
44 | self::assertInstanceOf(RedirectResponse::class, $redirect);
45 | self::assertSame('https://unavatar.io/github/Gummibeer', $redirect->getTargetUrl());
46 | }
47 |
48 | /** @test */
49 | public function it_is_responsable_json(): void
50 | {
51 | $unavatar = Unavatar::github('Gummibeer');
52 |
53 | self::assertArrayHasKey(Responsable::class, class_implements($unavatar));
54 |
55 | $request = Request::createFromGlobals();
56 | $request->headers->set('X-Requested-With', 'XMLHttpRequest');
57 | $response = $unavatar->toResponse($request);
58 |
59 | self::assertInstanceOf(JsonResponse::class, $response);
60 | $data = $response->getData(true);
61 | self::assertIsArray($data);
62 | self::assertArrayHasKey('url', $data);
63 | }
64 |
65 | /** @test */
66 | public function it_is_jsonable(): void
67 | {
68 | $unavatar = Unavatar::github('Gummibeer');
69 |
70 | self::assertArrayHasKey(Jsonable::class, class_implements($unavatar));
71 |
72 | $data = $unavatar->toJson();
73 | self::assertJson($data);
74 | $data = json_decode($data, true);
75 | self::assertIsArray($data);
76 | self::assertArrayHasKey('url', $data);
77 | }
78 |
79 | /** @test */
80 | public function it_is_arrayable(): void
81 | {
82 | $unavatar = Unavatar::github('Gummibeer');
83 |
84 | self::assertArrayHasKey(Arrayable::class, class_implements($unavatar));
85 |
86 | $data = $unavatar->toArray();
87 | self::assertIsArray($data);
88 | self::assertArrayHasKey('url', $data);
89 | }
90 |
91 | /** @test */
92 | public function it_is_arrayable_with_fallback(): void
93 | {
94 | $unavatar = Unavatar::github('Gummibeer')->fallback('https://example.com/avatar.jpg');
95 |
96 | self::assertArrayHasKey(Arrayable::class, class_implements($unavatar));
97 |
98 | $data = $unavatar->toArray();
99 | self::assertIsArray($data);
100 | self::assertArrayHasKey('url', $data);
101 | }
102 | }
103 |
--------------------------------------------------------------------------------