Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions components/ILIAS/Data/src/QR/ErrorCorrectionLevel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*/

declare(strict_types=1);

namespace ILIAS\Data\QR;

/**
* Error correction levels as defined by ISO/IEC 18004.
*
* Each level specifies the percentage of codewords that can be
* restored if the QR code is damaged or partially obscured.
* Please note that increasing the error correction level will
* decrease the data capacity of its payload.
*
* @see https://www.qrcode.com/en/about/error_correction.html
*/
enum ErrorCorrectionLevel: string
{
/** ~7% of codewords can be restored. */
case LOW = 'L';

/** ~15% of codewords can be restored (most fequently used). */
case MEDIUM = 'M';

/** ~25% of codewords can be restored. */
case QUARTILE = 'Q';

/** ~30% of codewords can be restored. */
case HIGH = 'H';
}
40 changes: 40 additions & 0 deletions components/ILIAS/Data/src/SVG.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*/

declare(strict_types=1);

namespace ILIAS\Data;

/**
* Data transfer object that carries the raw SVG data as a string,
* created from trusted sources. This object is merely a type as
* a mean to talk about SVG's and pass them between different layers
* of the system, it does not validate whether the SVG is valid or
* not.
*/
readonly class SVG implements \Stringable
{
public function __construct(
protected string $raw_svg_string,
) {
}

public function __toString(): string
{
return $this->raw_svg_string;
}
}
1 change: 1 addition & 0 deletions components/ILIAS/Refinery/src/String/Group.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use ILIAS\Refinery\Constraint;
use ILIAS\Refinery\Transformation;
use ILIAS\Refinery\String\Encoding\Group as EncodingGroup;
use ILIAS\Data\QR\ErrorCorrectionLevel;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
use ILIAS\Data\QR\ErrorCorrectionLevel;


class Group
{
Expand Down
19 changes: 16 additions & 3 deletions components/ILIAS/Refinery/src/URI/Group.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,25 @@

namespace ILIAS\Refinery\URI;

use ILIAS\Refinery\Transformation;
use ILIAS\Refinery\Transformation as ITransformation;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
use ILIAS\Refinery\Transformation as ITransformation;
use ILIAS\Refinery\Transformation;

use ILIAS\Data\QR\ErrorCorrectionLevel;

class Group
{
public function toString(): Transformation
public function toString(): ITransformation
{
return new StringTransformation();
return new Transformation\ToStringTransformation();
}

public function toSvg(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name toSvg says nothing about a QR code (same with the corresponding ToSvgTransformation class).
Please rename the method and transformation (maybe something like toSvgQRCode or so).

ErrorCorrectionLevel $error_correction_level = ErrorCorrectionLevel::MEDIUM,
int $size_in_px = 400,
): ITransformation {
return new Transformation\ToSvgTransformation($error_correction_level, $size_in_px);
}

public function fromSvg(): ITransformation
{
return new Transformation\FromSvgTransformation();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*/

declare(strict_types=1);

namespace ILIAS\Refinery\URI\Transformation;

use ILIAS\Refinery\DeriveApplyToFromTransform;
use ILIAS\Refinery\DeriveInvokeFromTransform;
use ILIAS\Refinery\Transformation;
use ILIAS\Data\SVG;

/**
* The {@see \ILIAS\Data\URI} does not support data URI yet, therefore
* this transformation currently returns a string.
*/
class FromSvgTransformation implements Transformation
{
use DeriveApplyToFromTransform;
use DeriveInvokeFromTransform;

protected const string SCHEME = 'data:';
protected const string MIME_TYPE = 'image/svg+xml';
protected const string ENCODING = 'base64';

public function transform(mixed $from): string
{
if (!$from instanceof SVG) {
throw new \InvalidArgumentException("Argument must be of type " . SVG::class);
}

return self::SCHEME . self::MIME_TYPE . ';' . self::ENCODING . ',' . base64_encode($from->__toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@

declare(strict_types=1);

namespace ILIAS\Refinery\URI;
namespace ILIAS\Refinery\URI\Transformation;

use ILIAS\Data\URI;
use ILIAS\Refinery\ConstraintViolationException;
use ILIAS\Refinery\DeriveApplyToFromTransform;
use ILIAS\Refinery\Transformation;
use ILIAS\Refinery\DeriveInvokeFromTransform;

class StringTransformation implements Transformation
class ToStringTransformation implements Transformation
{
use DeriveApplyToFromTransform;
use DeriveInvokeFromTransform;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*/

declare(strict_types=1);

namespace ILIAS\Refinery\URI\Transformation;

use ILIAS\Refinery\DeriveApplyToFromTransform;
use ILIAS\Refinery\DeriveInvokeFromTransform;
use ILIAS\Refinery\Transformation;
use ILIAS\Data\QR\ErrorCorrectionLevel;
use ILIAS\Data\SVG;
use ILIAS\Data\URI;
use BaconQrCode as External;

class ToSvgTransformation implements Transformation
{
use DeriveApplyToFromTransform;
use DeriveInvokeFromTransform;

protected const string ENCODING = 'UTF-8';

public function __construct(
protected ErrorCorrectionLevel $error_correction_level,
protected int $size_in_px,
) {
$this->assertIntGreaterThanZero($size_in_px);
}

public function transform(mixed $from): SVG
{
if (!$from instanceof URI) {
throw new \InvalidArgumentException("Argument must be of type " . URI::class);
}

$writer = new External\Writer(
new External\Renderer\ImageRenderer(
new External\Renderer\RendererStyle\RendererStyle($this->size_in_px),
new External\Renderer\Image\SvgImageBackEnd(),
),
);

$raw_svg_string = $writer->writeString(
$from->__toString(),
self::ENCODING,
$this->mapErrorCorrectionLevel($this->error_correction_level),
);

return new SVG($raw_svg_string);
}

protected function mapErrorCorrectionLevel(ErrorCorrectionLevel $level): External\Common\ErrorCorrectionLevel
{
return match ($level) {
ErrorCorrectionLevel::LOW => External\Common\ErrorCorrectionLevel::L(),
ErrorCorrectionLevel::MEDIUM => External\Common\ErrorCorrectionLevel::M(),
ErrorCorrectionLevel::QUARTILE => External\Common\ErrorCorrectionLevel::Q(),
ErrorCorrectionLevel::HIGH => External\Common\ErrorCorrectionLevel::H(),
};
}

protected function assertIntGreaterThanZero(int $number): void
{
if (0 >= $number) {
throw new \InvalidArgumentException("Number must be greater than zero.");
}
}
}
22 changes: 19 additions & 3 deletions components/ILIAS/Refinery/tests/URI/GroupTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,31 @@
namespace ILIAS\Tests\Refinery\URI;

use ILIAS\Refinery\URI\Group as URIGroup;
use ILIAS\Refinery\URI\StringTransformation;
use ILIAS\Refinery\URI\Transformation\ToStringTransformation;
use ILIAS\Refinery\URI\Transformation\FromSvgTransformation;
use ILIAS\Refinery\URI\Transformation\ToSvgTransformation;
use PHPUnit\Framework\TestCase;

class GroupTest extends TestCase
{
public function testStringTransformationInstance(): void
public function testToStringTransformationInstance(): void
{
$group = new URIGroup();
$transformation = $group->toString();
$this->assertInstanceOf(StringTransformation::class, $transformation);
$this->assertInstanceOf(ToStringTransformation::class, $transformation);
}

public function testToSvgTransformationInstance(): void
{
$group = new URIGroup();
$transformation = $group->toSvg();
$this->assertInstanceOf(ToSvgTransformation::class, $transformation);
}

public function testFromSvgTransformationInstance(): void
{
$group = new URIGroup();
$transformation = $group->fromSvg();
$this->assertInstanceOf(FromSvgTransformation::class, $transformation);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*/

declare(strict_types=1);

namespace ILIAS\Tests\Refinery\URI\Transformation;

use ILIAS\Refinery\URI\Transformation\FromSvgTransformation;
use PHPUnit\Framework\Attributes\Depends;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

class FromSvgTransformationTest extends TestCase
{
public function testTransformWithoutSvgInstance(): void
{
$transformation = new FromSvgTransformation();
$this->expectException(\InvalidArgumentException::class);
$transformation->transform('<svg></svg>');
}

public function testTransformWithSvgInstance(): void
{
$transformation = new FromSvgTransformation();
$this->expectNotToPerformAssertions();
$transformation->transform($this->createSvgMock());
}

#[Depends('testTransformWithSvgInstance')]
public function testTransformResult(): void
{
$transformation = new FromSvgTransformation();
$svg_mock = $this->createSvgMock();
$result = $transformation->transform($svg_mock);
$this->assertIsString($result);
$this->assertStringStartsWith("data:image/svg+xml;base64,", $result); // ensure correct data uri format
$this->assertStringEndsWith(base64_encode($svg_mock->__toString()), $result); // ensure base64 encoded value
}

protected function createSvgMock(): \ILIAS\Data\SVG & MockObject
{
$svg_mock = $this->createMock(\ILIAS\Data\SVG::class);
$svg_mock->method('__toString')->willReturn('<svg></svg>');
return $svg_mock;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@

declare(strict_types=1);

namespace ILIAS\Tests\Refinery\URI;
namespace ILIAS\Tests\Refinery\URI\Transformation;

use ILIAS\Data\URI;
use ILIAS\Refinery\ConstraintViolationException;
use ILIAS\Refinery\URI\StringTransformation;
use ILIAS\Refinery\URI\Transformation\ToStringTransformation;
use PHPUnit\Framework\TestCase;

class StringTransformationTest extends TestCase
{
private StringTransformation $transformation;
private ToStringTransformation $transformation;

protected function setUp(): void
{
$this->transformation = new StringTransformation();
$this->transformation = new ToStringTransformation();
}

public function testSimpleUri(): void
Expand Down
Loading
Loading