Skip to content

Commit

Permalink
Replaced ObHighchartsBundle by HighchartsBundle.
Browse files Browse the repository at this point in the history
  • Loading branch information
laurentmuller committed Oct 4, 2023
1 parent 75e421a commit a774360
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 269 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/psalm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ jobs:
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

- name: Run psalm
run: vendor-bin/psalm/vendor/bin/psalm src
run: vendor-bin/psalm/vendor/bin/psalm --config=psalm.xml
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
"repositories": [
{
"type": "vcs",
"url": "https://github.com/laurentmuller/ObHighchartsBundle"
"url": "https://github.com/laurentmuller/HighchartsBundle"
},
{
"type": "vcs",
Expand Down
27 changes: 14 additions & 13 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion config/bundles.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Createnl\ZxcvbnBundle\ZxcvbnBundle::class => ['all' => true],
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
Elao\Enum\Bridge\Symfony\Bundle\ElaoEnumBundle::class => ['all' => true],
Ob\HighchartsBundle\ObHighchartsBundle::class => ['all' => true],
HighchartsBundle\HighchartsBundle::class => ['all' => true],
SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true],
SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
Expand Down
4 changes: 2 additions & 2 deletions src/Chart/AbstractHighchart.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
use App\Traits\TranslatorAwareTrait;
use App\Utils\DateUtils;
use App\Utils\FormatUtils;
use Ob\HighchartsBundle\Highcharts\ChartOption;
use Ob\HighchartsBundle\Highcharts\Highchart;
use HighchartsBundle\Highcharts\ChartOption;
use HighchartsBundle\Highcharts\Highchart;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
use Symfony\Contracts\Service\ServiceSubscriberTrait;

Expand Down
18 changes: 12 additions & 6 deletions src/Enums/ImageExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace App\Enums;

use App\Interfaces\EnumDefaultInterface;
use App\Service\ImageService;
use App\Traits\EnumDefaultTrait;
use Elao\Enum\Attribute\EnumCase;

Expand Down Expand Up @@ -83,7 +84,7 @@ enum ImageExtension: string implements EnumDefaultInterface
*
* @return \GdImage|false an image resource identifier on success, false on error
*/
public function create(string $filename): \GdImage|false
public function createImage(string $filename): \GdImage|false
{
return match ($this) {
ImageExtension::BMP => \imagecreatefrombmp($filename),
Expand All @@ -101,18 +102,23 @@ public function create(string $filename): \GdImage|false
/**
* Output an image to either the browser or a file.
*
* @param \GdImage $image a GdImage object, returned by one of the image creation functions
* @param resource|string|null $file The path or an open stream resource, which is automatically closed after this
* function returns; to save the file to. If not set or null, the raw image
* stream will be output directly.
* @param \GdImage|ImageService $image a GdImage object, returned by one of the image creation functions or an
* image service to get GdImage for
* @param resource|string|null $file The path or an open stream resource, which is automatically closed after
* this function returns; to save the file to. If not set or null, the raw
* image stream will be output directly.
* @param array<string, int|bool> $options additional options to use
*
* @return bool true on success or false on failure
*
* @psalm-param SaveOptionsType $options
*/
public function save(\GdImage $image, mixed $file = null, array $options = []): bool
public function saveImage(\GdImage|ImageService $image, mixed $file = null, array $options = []): bool
{
if ($image instanceof ImageService) {
$image = $image->getImage();
}

return match ($this) {
ImageExtension::BMP => \imagebmp($image, $file, $options['compressed'] ?? true),
ImageExtension::GIF => \imagegif($image, $file),
Expand Down
115 changes: 62 additions & 53 deletions src/Service/CaptchaImageService.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

namespace App\Service;

use App\Enums\ImageExtension;
use App\Traits\SessionAwareTrait;
use App\Utils\StringUtils;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
Expand All @@ -20,6 +21,12 @@

/**
* Service to generate and validate a captcha image.
*
* @psalm-type ComputeTextType = array{
* char: string,
* angle: int,
* height: int,
* width: int}
*/
class CaptchaImageService implements ServiceSubscriberInterface
{
Expand Down Expand Up @@ -88,7 +95,7 @@ public function clear(): self
* @param int $width the image width
* @param int $height the image height
*
* @return string|null the image encoded with the base 64 or null if the image canot be created
* @return string|null the image encoded with the base 64 or null if the image can not be created
*
* @throws \Exception
*/
Expand All @@ -97,21 +104,22 @@ public function generateImage(bool $force = false, int $length = 6, int $width =
if (!$force && $this->validateTimeout() && $this->hasSessionValue(self::KEY_DATA)) {
return $this->getSessionString(self::KEY_DATA);
}

$this->clear();
$text = $this->generateRandomString($length);
$image = $this->createImage($text, $width, $height);
if ($image instanceof ImageService) {
$data = $this->encodeImage($image);
$this->setSessionValues([
self::KEY_TEXT => $text,
self::KEY_DATA => $data,
self::KEY_TIME => \time(),
]);

return $data;
if (!$image instanceof ImageService) {
return null;
}

return null;
$data = $this->encodeImage($image);
$this->setSessionValues([
self::KEY_TEXT => $text,
self::KEY_DATA => $data,
self::KEY_TIME => \time(),
]);

return $data;
}

/**
Expand All @@ -137,7 +145,7 @@ public function validateToken(?string $token): bool
/**
* Compute the text layout.
*
* @pslam-return array<array{angle: int(-8, 8), char: string, height: int, width: int}>
* @pslam-return non-empty-array<ComputeTextType>
*
* @throws \Exception
*/
Expand Down Expand Up @@ -167,91 +175,92 @@ private function createImage(string $text, int $width, int $height): ?ImageServi
if (!$image instanceof ImageService) {
return null;
}
$this->drawBackground($image)
->drawPoints($image, $width, $height)
->drawLines($image, $width, $height)
->drawText($image, $width, $height, $text);

$this->drawBackground($image);
$this->drawPoints($image, $width, $height);
$this->drawLines($image, $width, $height);
$this->drawText($image, $width, $height, $text);

return $image;
}

/**
* Draws the white background image.
*/
private function drawBackground(ImageService $image): self
private function drawBackground(ImageService $image): void
{
$color = $image->allocateWhite();
if (\is_int($color)) {
$image->fill($color);
if (!\is_int($color)) {
return;
}

return $this;
$image->fill($color);
}

/**
* Draws horizontal gray lines in the background.
*
* @throws \Exception
*/
private function drawLines(ImageService $image, int $width, int $height): self
private function drawLines(ImageService $image, int $width, int $height): void
{
$color = $image->allocate(195, 195, 195);
if (\is_int($color)) {
$lines = \random_int(3, 7);
for ($i = 0; $i < $lines; ++$i) {
$y1 = \random_int(0, $height);
$y2 = \random_int(0, $height);
$image->line(0, $y1, $width, $y2, $color);
}
if (!\is_int($color)) {
return;
}

return $this;
$lines = \random_int(3, 7);
for ($i = 0; $i < $lines; ++$i) {
$y1 = \random_int(0, $height);
$y2 = \random_int(0, $height);
$image->line(0, $y1, $width, $y2, $color);
}
}

/**
* Draws blue points in the background.
*
* @throws \Exception
*/
private function drawPoints(ImageService $image, int $width, int $height): self
private function drawPoints(ImageService $image, int $width, int $height): void
{
$color = $image->allocate(0, 0, 255);
if (\is_int($color)) {
$points = \random_int(300, 400);
for ($i = 0; $i < $points; ++$i) {
$x = \random_int(0, $width);
$y = \random_int(0, $height);
$image->setPixel($x, $y, $color);
}
if (!\is_int($color)) {
return;
}

return $this;
$points = \random_int(300, 400);
for ($i = 0; $i < $points; ++$i) {
$x = \random_int(0, $width);
$y = \random_int(0, $height);
$image->setPixel($x, $y, $color);
}
}

/**
* Draws the image text.
*
* @throws \Exception
*/
private function drawText(ImageService $image, int $width, int $height, string $text): self
private function drawText(ImageService $image, int $width, int $height, string $text): void
{
$font = $this->font;
$color = $image->allocateBlack();
if (\is_int($color)) {
$size = (int) ((float) $height * 0.7);
/** @psalm-var non-empty-array<array{angle: int, char: string, height: int, width: int}> $items */
$items = $this->computeText($image, $size, $font, $text);
$textHeight = \max(\array_column($items, 'height'));
$textWidth = \array_sum(\array_column($items, 'width')) + (\count($items) - 1) * self::CHAR_SPACE;
$x = \intdiv($width - $textWidth, 2);
$y = \intdiv($height - $textHeight, 2) + $size;
foreach ($items as $item) {
$image->ttfText($size, $item['angle'], $x, $y, $color, $font, $item['char']);
$x += $item['width'] + self::CHAR_SPACE;
}
if (!\is_int($color)) {
return;
}

return $this;
$size = (int) ((float) $height * 0.7);
/** @psalm-var non-empty-array<ComputeTextType> $items */
$items = $this->computeText($image, $size, $font, $text);
$textHeight = \max(\array_column($items, 'height'));
$textWidth = \array_sum(\array_column($items, 'width')) + (\count($items) - 1) * self::CHAR_SPACE;
$x = \intdiv($width - $textWidth, 2);
$y = \intdiv($height - $textHeight, 2) + $size;
foreach ($items as $item) {
$image->ttfText($size, $item['angle'], $x, $y, $color, $font, $item['char']);
$x += $item['width'] + self::CHAR_SPACE;
}
}

/**
Expand All @@ -260,7 +269,7 @@ private function drawText(ImageService $image, int $width, int $height, string $
private function encodeImage(ImageService $image): string
{
\ob_start();
$image->toPng();
ImageExtension::PNG->saveImage($image);
$buffer = (string) \ob_get_contents();
\ob_end_clean();

Expand Down
Loading

0 comments on commit a774360

Please sign in to comment.