Skip to content

Commit

Permalink
Refactor to Introduce QR Code Types and Factory
Browse files Browse the repository at this point in the history
Removed `QrCodeCommand` and added new types: `PhoneNumberQrCode`, `EmailQrCode`, `WifiQrCode`, and `TextQrCode`. Implemented a `QrCodeFactory` for instantiating these types. Improved `QrCode` class with configurable parameters and added comprehensive tests to validate functionality and error handling.
  • Loading branch information
Dominik Eller committed Sep 20, 2024
1 parent a3891c7 commit d8872de
Show file tree
Hide file tree
Showing 20 changed files with 583 additions and 26 deletions.
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
}
],
"require": {
"bacon/bacon-qr-code": "^3.0",
"ext-gd": "*",
"php": "^8.2",
"spatie/laravel-package-tools": "^1.16",
"illuminate/contracts": "^10.0||^11.0"
Expand Down Expand Up @@ -81,4 +83,4 @@
},
"minimum-stability": "dev",
"prefer-stable": true
}
}
19 changes: 0 additions & 19 deletions src/Commands/QrCodeCommand.php

This file was deleted.

4 changes: 2 additions & 2 deletions src/Facades/QrCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
*/
class QrCode extends Facade
{
protected static function getFacadeAccessor(): string
protected static function getFacadeAccessor()
{
return \Deller\QrCode\QrCode::class;
return 'qr-code'; // This should match the binding name in the service provider
}
}
50 changes: 50 additions & 0 deletions src/Factories/QrCodeFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Deller\QrCode\Factories;

use Deller\QrCode\QrCode;
use Deller\QrCode\Types\EmailQrCode;
use Deller\QrCode\Types\PhoneNumberQrCode;
use Deller\QrCode\Types\TextQrCode;
use Deller\QrCode\Types\UrlQrCode;
use InvalidArgumentException;

class QrCodeFactory
{
protected static $types = [
'url' => UrlQrCode::class,
'text' => TextQrCode::class,
'email' => EmailQrCode::class,
'phone' => PhoneNumberQrCode::class,
];

/**
* Create a QR code generator based on type.
*
* @param string $type
* @return QrCode
* @throws InvalidArgumentException
*/
public static function create(string $type): QrCode
{
if (!array_key_exists($type, self::$types)) {
throw new InvalidArgumentException("QR code type [$type] is not supported.");
}

$className = self::$types[$type];

return new $className();
}

/**
* Register a custom QR code type.
*
* @param string $type
* @param string $class
* @return void
*/
public static function registerType(string $type, string $class)
{
self::$types[$type] = $class;
}
}
169 changes: 168 additions & 1 deletion src/QrCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,171 @@

namespace Deller\QrCode;

class QrCode {}
use BaconQrCode\Common\ErrorCorrectionLevel;
use BaconQrCode\Renderer\Color\Rgb;
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
use BaconQrCode\Renderer\RendererStyle\Fill;
use BaconQrCode\Renderer\RendererStyle\EyeFill;
use BaconQrCode\Renderer\ImageRenderer;
use BaconQrCode\Writer;

abstract class QrCode
{
protected $errorCorrectionLevel;
protected $size = 300;
protected $color = [0, 0, 0]; // Default to black
protected $backgroundColor = [255, 255, 255]; // Default to white
protected $margin = 10;
protected $topLeftEyeColor = [0, 0, 0];
protected $topRightEyeColor = [0, 0, 0];
protected $bottomLeftEyeColor = [0, 0, 0];

public function __construct()
{
$this->errorCorrectionLevel = ErrorCorrectionLevel::M(); // Default to medium
}

public function setSize(int $size)
{
$this->size = $size;
return $this;
}

public function setColor(array $color)
{
$this->color = $color;
return $this;
}

public function setBackgroundColor(array $backgroundColor)
{
$this->backgroundColor = $backgroundColor;
return $this;
}

public function setMargin(int $margin)
{
$this->margin = $margin;
return $this;
}

public function setErrorCorrectionLevel(string $level)
{
switch (strtoupper($level)) {
case 'L':
$this->errorCorrectionLevel = ErrorCorrectionLevel::L();
break;
case 'M':
$this->errorCorrectionLevel = ErrorCorrectionLevel::M();
break;
case 'Q':
$this->errorCorrectionLevel = ErrorCorrectionLevel::Q();
break;
case 'H':
$this->errorCorrectionLevel = ErrorCorrectionLevel::H();
break;
default:
throw new \InvalidArgumentException("Invalid error correction level: $level");
}
return $this;
}

public function setTopLeftEyeColor(array $color)
{
$this->topLeftEyeColor = $color;
return $this;
}

public function setTopRightEyeColor(array $color)
{
$this->topRightEyeColor = $color;
return $this;
}

public function setBottomLeftEyeColor(array $color)
{
$this->bottomLeftEyeColor = $color;
return $this;
}

public function getSize(): int
{
return $this->size;
}

public function getColor(): array
{
return $this->color;
}

public function getMargin(): int
{
return $this->margin;
}

public function getBackgroundColor(): array
{
return $this->backgroundColor;
}

public function getErrorCorrectionLevel(): ErrorCorrectionLevel
{
return $this->errorCorrectionLevel;
}

public function getTopLeftEyeColor(): array
{
return $this->topLeftEyeColor;
}

public function getTopRightEyeColor(): array
{
return $this->topRightEyeColor;
}

public function getBottomLeftEyeColor(): array
{
return $this->bottomLeftEyeColor;
}

abstract public function getData(): string;

public function generate(): string
{
// Create the eye fills for the three QR code corners
$topLeftEyeFill = EyeFill::uniform(new Rgb(...$this->topLeftEyeColor));
$topRightEyeFill = EyeFill::uniform(new Rgb(...$this->topRightEyeColor));
$bottomLeftEyeFill = EyeFill::uniform(new Rgb(...$this->bottomLeftEyeColor));

// Create the fill object for the foreground and background colors
$fill = Fill::withForegroundColor(
new Rgb(...$this->backgroundColor), // Background color
new Rgb(...$this->color), // Foreground color
$topLeftEyeFill, // Top-left eye fill
$topRightEyeFill, // Top-right eye fill
$bottomLeftEyeFill // Bottom-left eye fill
);

// Create the RendererStyle object with proper parameters
$style = new RendererStyle(
$this->size, // Module size
$this->margin, // Margin
null, // No custom module style
null, // No custom eye design (only using eye colors)
$fill // Pass the custom fill object
);

// Create the ImageRenderer with the Imagick backend
$renderer = new ImageRenderer(
$style,
new \BaconQrCode\Renderer\Image\ImagickImageBackEnd()
);

// Create the Writer with the renderer
$writer = new Writer($renderer);

// Generate the QR code with the data provided
return $writer->writeString($this->getData());
}

}
12 changes: 9 additions & 3 deletions src/QrCodeServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Deller\QrCode;

use Deller\QrCode\Factories\QrCodeFactory;
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;
use Deller\QrCode\Commands\QrCodeCommand;
Expand All @@ -18,8 +19,13 @@ public function configurePackage(Package $package): void
$package
->name('laravel-qr-code')
->hasConfigFile()
->hasViews()
->hasMigration('create_laravel_qr_code_table')
->hasCommand(QrCodeCommand::class);
->hasViews();
}

public function packageRegistered()
{
$this->app->singleton('qr-code', function ($app) {
return new QrCodeFactory();
});
}
}
32 changes: 32 additions & 0 deletions src/Types/EmailQrCode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Deller\QrCode\Types;

use Deller\QrCode\QrCode;

class EmailQrCode extends QrCode
{
protected $email;

/**
* Set the email address for the QR code.
*
* @param string $email
* @return $this
*/
public function setEmail(string $email)
{
$this->email = $email;
return $this;
}

/**
* Return the formatted email data for the QR code.
*
* @return string
*/
public function getData(): string
{
return "mailto:" . $this->email;
}
}
32 changes: 32 additions & 0 deletions src/Types/PhoneNumberQrCode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Deller\QrCode\Types;

use Deller\QrCode\QrCode;

class PhoneNumberQrCode extends QrCode
{
protected $phoneNumber;

/**
* Set the phone number for the QR code.
*
* @param string $phoneNumber
* @return $this
*/
public function setPhoneNumber(string $phoneNumber)
{
$this->phoneNumber = $phoneNumber;
return $this;
}

/**
* Return the formatted phone number data for the QR code.
*
* @return string
*/
public function getData(): string
{
return "tel:" . $this->phoneNumber;
}
}
21 changes: 21 additions & 0 deletions src/Types/TextQrCode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Deller\QrCode\Types;

use Deller\QrCode\QrCode;

class TextQrCode extends QrCode
{
protected $text;

public function setText(string $text)
{
$this->text = $text;
return $this;
}

public function getData(): string
{
return $this->text;
}
}
Loading

0 comments on commit d8872de

Please sign in to comment.