From 5c81fbf0d68ee3d12257fc2c2d73482ee6addafb Mon Sep 17 00:00:00 2001
From: Anton Komarev <1849174+antonkomarev@users.noreply.github.com>
Date: Mon, 20 Jul 2020 22:17:33 +0300
Subject: [PATCH] Make badge style customizable (#8)
* Add Poser badge generator
* Make badge styles configurable
* Make flat style as default
---
README.md | 18 ++
composer.json | 1 +
composer.lock | 319 +++++++++++++++++++++++++++++-
public/file-repository.php | 17 +-
public/pdo-repository.php | 19 +-
resources/badge.svg | 11 --
src/BadgeImageRendererService.php | 60 ++----
7 files changed, 377 insertions(+), 68 deletions(-)
delete mode 100644 resources/badge.svg
diff --git a/README.md b/README.md
index 4f5f5af..8d8d48e 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,24 @@ You need to add counter in README.md file in your profile repository via Markdow
> **NOTE**: Don't forget to replace example `username` parameter with real value.
+### Customization
+
+#### Styles
+
+The following styles are available (`flat` is the default):
+
+| style | demo |
+| ----- | ---- |
+| `flat` |  |
+| `flat-square` |  |
+| `plastic` |  |
+
+```markdown
+
+```
+
+For example
+
## Is it safe to place tracking image?
GitHub passes all images URLs through their proxy _camo_ service. URLs are look like [https://camo.githubusercontent.com/a9aa69b588bef281647d53091b4faa01ac126121/68747470733a2f2f6b6f6d617265762e636f6d2f67687076632f3f757365726e616d653d616e746f6e6b6f6d6172657626](https://camo.githubusercontent.com/a9aa69b588bef281647d53091b4faa01ac126121/68747470733a2f2f6b6f6d617265762e636f6d2f67687076632f3f757365726e616d653d616e746f6e6b6f6d6172657626).
diff --git a/composer.json b/composer.json
index 3c43944..71e59cd 100644
--- a/composer.json
+++ b/composer.json
@@ -27,6 +27,7 @@
},
"require": {
"php": "^7.4",
+ "badges/poser": "^1.4",
"vlucas/phpdotenv": "^5.0",
"webmozart/assert": "^1.9"
},
diff --git a/composer.lock b/composer.lock
index 94a019e..36209e2 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,75 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "1199b144b9fb9e5178e80602812dd8b2",
+ "content-hash": "268e668398fa52181cf35d8920a04ab9",
"packages": [
+ {
+ "name": "badges/poser",
+ "version": "v1.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/badges/poser.git",
+ "reference": "4281890cbd58e0ea29c6550c4a4aaa16a15b3ce0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/badges/poser/zipball/4281890cbd58e0ea29c6550c4a4aaa16a15b3ce0",
+ "reference": "4281890cbd58e0ea29c6550c4a4aaa16a15b3ce0",
+ "shasum": ""
+ },
+ "require": {
+ "ext-gd": "*",
+ "php": ">=5.3",
+ "symfony/console": "~2.0|~3.0|~4.0"
+ },
+ "require-dev": {
+ "behat/behat": "^3.4",
+ "coduo/phpspec-data-provider-extension": "^1.0",
+ "friendsofphp/php-cs-fixer": "@stable",
+ "phpspec/phpspec": "^2.5"
+ },
+ "bin": [
+ "bin/poser"
+ ],
+ "type": "lib",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PUGX\\Poser\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Giulio De Donato",
+ "email": "liuggio@gmail.com"
+ },
+ {
+ "name": "PUGX Community",
+ "homepage": "https://github.com/PUGX/badge-poser/contributors"
+ },
+ {
+ "name": "Shields Community",
+ "homepage": "https://github.com/badges/poser/contributors"
+ }
+ ],
+ "description": "Poser, add badges on your readme..",
+ "homepage": "https://github.com/PUGX",
+ "keywords": [
+ "badge",
+ "composer",
+ "packagist",
+ "pin"
+ ],
+ "time": "2020-06-11T16:17:31+00:00"
+ },
{
"name": "graham-campbell/result-type",
"version": "v1.0.1",
@@ -113,6 +180,132 @@
],
"time": "2020-06-07T10:40:07+00:00"
},
+ {
+ "name": "psr/container",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+ "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "time": "2017-02-14T16:28:37+00:00"
+ },
+ {
+ "name": "symfony/console",
+ "version": "v4.4.10",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/console.git",
+ "reference": "326b064d804043005526f5a0494cfb49edb59bb0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/console/zipball/326b064d804043005526f5a0494cfb49edb59bb0",
+ "reference": "326b064d804043005526f5a0494cfb49edb59bb0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.3",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/polyfill-php73": "^1.8",
+ "symfony/polyfill-php80": "^1.15",
+ "symfony/service-contracts": "^1.1|^2"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<3.4",
+ "symfony/event-dispatcher": "<4.3|>=5",
+ "symfony/lock": "<4.4",
+ "symfony/process": "<3.3"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0"
+ },
+ "require-dev": {
+ "psr/log": "~1.0",
+ "symfony/config": "^3.4|^4.0|^5.0",
+ "symfony/dependency-injection": "^3.4|^4.0|^5.0",
+ "symfony/event-dispatcher": "^4.3",
+ "symfony/lock": "^4.4|^5.0",
+ "symfony/process": "^3.4|^4.0|^5.0",
+ "symfony/var-dumper": "^4.3|^5.0"
+ },
+ "suggest": {
+ "psr/log": "For using the console logger",
+ "symfony/event-dispatcher": "",
+ "symfony/lock": "",
+ "symfony/process": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Console\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Console Component",
+ "homepage": "https://symfony.com",
+ "time": "2020-05-30T20:06:45+00:00"
+ },
{
"name": "symfony/polyfill-ctype",
"version": "v1.17.1",
@@ -238,6 +431,68 @@
],
"time": "2020-06-06T08:46:27+00:00"
},
+ {
+ "name": "symfony/polyfill-php73",
+ "version": "v1.18.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php73.git",
+ "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fffa1a52a023e782cdcc221d781fe1ec8f87fcca",
+ "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.18-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php73\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "time": "2020-07-14T12:35:20+00:00"
+ },
{
"name": "symfony/polyfill-php80",
"version": "v1.17.1",
@@ -304,6 +559,68 @@
],
"time": "2020-06-06T08:46:27+00:00"
},
+ {
+ "name": "symfony/service-contracts",
+ "version": "v2.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "58c7475e5457c5492c26cc740cc0ad7464be9442"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/58c7475e5457c5492c26cc740cc0ad7464be9442",
+ "reference": "58c7475e5457c5492c26cc740cc0ad7464be9442",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.5",
+ "psr/container": "^1.0"
+ },
+ "suggest": {
+ "symfony/service-implementation": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.1-dev"
+ },
+ "thanks": {
+ "name": "symfony/contracts",
+ "url": "https://github.com/symfony/contracts"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Service\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to writing services",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "time": "2020-07-06T13:23:11+00:00"
+ },
{
"name": "vlucas/phpdotenv",
"version": "v5.0.0",
diff --git a/public/file-repository.php b/public/file-repository.php
index e69f33a..c2dbb15 100644
--- a/public/file-repository.php
+++ b/public/file-repository.php
@@ -30,8 +30,6 @@ try {
$dotEnv = Dotenv::createImmutable($basePath);
$dotEnv->safeLoad();
- $badgeImagePath = $basePath . '/resources/badge.svg';
-
$httpUserAgent = $_SERVER['HTTP_USER_AGENT'];
if (!isset($_ENV['FILE_STORAGE_PATH']) || $_ENV['FILE_STORAGE_PATH'] === null) {
@@ -40,12 +38,15 @@ try {
$storagePath = $_ENV['FILE_STORAGE_PATH'];
}
- $style = $_GET['style'] ?? null;
+ $badgeStyle = $_GET['style'] ?? 'flat';
+ if (!in_array($badgeStyle, ['flat', 'flat-square', 'plastic'])) {
+ $badgeStyle = 'flat';
+ }
$username = $_GET['username'] ?? '';
$username = trim($username);
if ($username === '') {
- echo $badgeImageRenderer->renderBadgeWithError($badgeImagePath, 'Invalid query parameter: username');
+ echo $badgeImageRenderer->renderBadgeWithError($badgeStyle, 'Invalid query parameter: username');
exit;
}
@@ -57,16 +58,16 @@ try {
$counterRepository->addViewByUsername($username);
}
- if ($style === 'pixel') {
- echo '';
+ if ($badgeStyle === 'pixel') {
+ echo $badgeImageRenderer->renderPixel();
exit;
}
$count = $counterRepository->getViewsCountByUsername($username);
- echo $badgeImageRenderer->renderBadgeWithCount($badgeImagePath, $count);
+ echo $badgeImageRenderer->renderBadgeWithCount($badgeStyle, $count);
exit;
} catch (Exception $exception) {
- echo $badgeImageRenderer->renderBadgeWithError($badgeImagePath, $exception->getMessage());
+ echo $badgeImageRenderer->renderBadgeWithError($badgeStyle, $exception->getMessage());
exit;
}
diff --git a/public/pdo-repository.php b/public/pdo-repository.php
index bfcdaec..6683ff3 100644
--- a/public/pdo-repository.php
+++ b/public/pdo-repository.php
@@ -40,16 +40,17 @@ try {
'DB_NAME',
]);
- $badgeImagePath = $basePath . '/resources/badge.svg';
-
$httpUserAgent = $_SERVER['HTTP_USER_AGENT'];
- $style = $_GET['style'] ?? null;
+ $badgeStyle = $_GET['style'] ?? 'flat';
+ if (!in_array($badgeStyle, ['flat', 'flat-square', 'plastic'])) {
+ $badgeStyle = 'flat';
+ }
$username = $_GET['username'] ?? '';
$username = trim($username);
if ($username === '') {
- echo $badgeImageRenderer->renderBadgeWithError($badgeImagePath, 'Invalid query parameter: username');
+ echo $badgeImageRenderer->renderBadgeWithError($badgeStyle, 'Invalid query parameter: username');
exit;
}
@@ -70,19 +71,19 @@ try {
$counterRepository->addViewByUsername($username);
}
- if ($style === 'pixel') {
- echo '';
+ if ($badgeStyle === 'pixel') {
+ echo $badgeImageRenderer->renderPixel();
exit;
}
$count = $counterRepository->getViewsCountByUsername($username);
- echo $badgeImageRenderer->renderBadgeWithCount($badgeImagePath, $count);
+ echo $badgeImageRenderer->renderBadgeWithCount($badgeStyle, $count);
exit;
} catch (InvalidPathException $exception) {
- echo $badgeImageRenderer->renderBadgeWithError($badgeImagePath, 'Application environment file is missing');
+ echo $badgeImageRenderer->renderBadgeWithError($badgeStyle, 'Application environment file is missing');
exit;
} catch (Exception $exception) {
- echo $badgeImageRenderer->renderBadgeWithError($badgeImagePath, $exception->getMessage());
+ echo $badgeImageRenderer->renderBadgeWithError($badgeStyle, $exception->getMessage());
exit;
}
diff --git a/resources/badge.svg b/resources/badge.svg
deleted file mode 100644
index c154072..0000000
--- a/resources/badge.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/src/BadgeImageRendererService.php b/src/BadgeImageRendererService.php
index f74a26a..3796bfb 100644
--- a/src/BadgeImageRendererService.php
+++ b/src/BadgeImageRendererService.php
@@ -13,61 +13,43 @@ declare(strict_types=1);
namespace Komarev\GitHubProfileViewsCounter;
-use Contracts\Komarev\GitHubProfileViewsCounter\InvalidPathException;
+use PUGX\Poser\Poser;
+use PUGX\Poser\Render\SvgFlatRender;
+use PUGX\Poser\Render\SvgFlatSquareRender;
+use PUGX\Poser\Render\SvgRender;
final class BadgeImageRendererService
{
- public function renderBadgeWithCount(string $imagePath, int $count): string
+ private Poser $poser;
+
+ public function __construct()
+ {
+ $this->poser = new Poser([new SvgRender(), new SvgFlatRender(), new SvgFlatSquareRender()]);
+ }
+
+ public function renderBadgeWithCount($badgeStyle, int $count): string
{
$message = (string) $count;
- $messageBackgroundFill = '#007ec6';
+ $messageBackgroundFill = '007ec6';
- return $this->renderBadge($imagePath, $message, $messageBackgroundFill);
+ return $this->renderBadge($badgeStyle, $message, $messageBackgroundFill);
}
- public function renderBadgeWithError(string $imagePath, string $message): string
+ public function renderBadgeWithError($badgeStyle, string $message): string
{
- $messageBackgroundFill = '#e05d44';
+ $messageBackgroundFill = 'e05d44';
- return $this->renderBadge($imagePath, $message, $messageBackgroundFill);
+ return $this->renderBadge($badgeStyle, $message, $messageBackgroundFill);
}
- private function renderBadge(string $imagePath, string $message, string $messageBackgroundFill): string
+ private function renderBadge($badgeStyle, string $message, string $messageBackgroundFill): string
{
- if (!file_exists($imagePath)) {
- throw new InvalidPathException('Badge image not found');
- }
-
- $image = file_get_contents($imagePath);
-
-
- return $this->replaceImagePlaceholders($image, $message, $messageBackgroundFill);
+ return (string) $this->poser->generate('Page views', $message, $messageBackgroundFill, $badgeStyle);
}
- private function replaceImagePlaceholders(string $image, string $message, string $messageBackgroundFill): string
+ public function renderPixel(): string
{
- $messageLength = strlen($message);
-
- $minImageWidth = 98;
- $minMessageBackgroundWidth = 17;
- $minMessageTextLength = 70;
- $minMessageTextMarginLeft = 885;
-
- $label = 'Profile views';
- $imageWidth = $minImageWidth + (8 * $messageLength);
- $messageBackgroundWidth = $minMessageBackgroundWidth + (8 * $messageLength);
- $messageTextLength = $minMessageTextLength + (80 * $messageLength);
- $messageTextMarginLeft = $minMessageTextMarginLeft + (40 * $messageLength);
-
- $image = str_replace('%IMAGE_WIDTH%', $imageWidth, $image);
- $image = str_replace('%LABEL%', $label, $image);
- $image = str_replace('%MESSAGE%', $message, $image);
- $image = str_replace('%MESSAGE_BACKGROUND_WIDTH%', $messageBackgroundWidth, $image);
- $image = str_replace('%MESSAGE_BACKGROUND_FILL%', $messageBackgroundFill, $image);
- $image = str_replace('%MESSAGE_TEXT_LENGTH%', $messageTextLength, $image);
- $image = str_replace('%MESSAGE_TEXT_MARGIN_LEFT%', $messageTextMarginLeft, $image);
-
- return $image;
+ return '';
}
}