Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
167
src/Framework/QrCode/Structure/BlockStructure.php
Normal file
167
src/Framework/QrCode/Structure/BlockStructure.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\QrCode\Structure;
|
||||
|
||||
use App\Framework\QrCode\ReedSolomon\ReedSolomonEncoder;
|
||||
|
||||
/**
|
||||
* QR Code Block Structure Manager
|
||||
*
|
||||
* Handles data block division and error correction code generation
|
||||
* according to QR code specification
|
||||
*/
|
||||
final class BlockStructure
|
||||
{
|
||||
private ReedSolomonEncoder $encoder;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->encoder = new ReedSolomonEncoder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create blocks from data codewords
|
||||
*/
|
||||
public function createBlocks(array $dataCodewords, int $version, string $errorLevel): array
|
||||
{
|
||||
$blockInfo = $this->getBlockInfo($version, $errorLevel);
|
||||
|
||||
$blocks = [];
|
||||
$dataOffset = 0;
|
||||
|
||||
// Create Group 1 blocks (if any)
|
||||
for ($i = 0; $i < $blockInfo['group1_blocks']; $i++) {
|
||||
$blockData = array_slice(
|
||||
$dataCodewords,
|
||||
$dataOffset,
|
||||
$blockInfo['group1_data_per_block']
|
||||
);
|
||||
|
||||
$errorCodewords = $this->encoder->encode(
|
||||
$blockData,
|
||||
$blockInfo['error_correction_per_block']
|
||||
);
|
||||
|
||||
$blocks[] = new QrCodeBlock(
|
||||
$blockData,
|
||||
array_slice($errorCodewords, count($blockData))
|
||||
);
|
||||
|
||||
$dataOffset += $blockInfo['group1_data_per_block'];
|
||||
}
|
||||
|
||||
// Create Group 2 blocks (if any)
|
||||
for ($i = 0; $i < $blockInfo['group2_blocks']; $i++) {
|
||||
$blockData = array_slice(
|
||||
$dataCodewords,
|
||||
$dataOffset,
|
||||
$blockInfo['group2_data_per_block']
|
||||
);
|
||||
|
||||
$errorCodewords = $this->encoder->encode(
|
||||
$blockData,
|
||||
$blockInfo['error_correction_per_block']
|
||||
);
|
||||
|
||||
$blocks[] = new QrCodeBlock(
|
||||
$blockData,
|
||||
array_slice($errorCodewords, count($blockData))
|
||||
);
|
||||
|
||||
$dataOffset += $blockInfo['group2_data_per_block'];
|
||||
}
|
||||
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interleave data and error correction codewords from blocks
|
||||
*/
|
||||
public function interleaveBlocks(array $blocks): array
|
||||
{
|
||||
if (empty($blocks)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
// Interleave data codewords
|
||||
$maxDataLength = max(array_map(fn ($block) => $block->getDataLength(), $blocks));
|
||||
|
||||
for ($i = 0; $i < $maxDataLength; $i++) {
|
||||
foreach ($blocks as $block) {
|
||||
if ($i < $block->getDataLength()) {
|
||||
$result[] = $block->dataCodewords[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interleave error correction codewords
|
||||
$maxEcLength = max(array_map(fn ($block) => $block->getErrorCorrectionLength(), $blocks));
|
||||
|
||||
for ($i = 0; $i < $maxEcLength; $i++) {
|
||||
foreach ($blocks as $block) {
|
||||
if ($i < $block->getErrorCorrectionLength()) {
|
||||
$result[] = $block->errorCorrectionCodewords[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get block structure information for version and error level
|
||||
*/
|
||||
private function getBlockInfo(int $version, string $errorLevel): array
|
||||
{
|
||||
// Block structure lookup table for QR versions 1-10 (simplified for now)
|
||||
$blockStructures = [
|
||||
1 => [
|
||||
'L' => ['group1_blocks' => 1, 'group1_data_per_block' => 19, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 7],
|
||||
'M' => ['group1_blocks' => 1, 'group1_data_per_block' => 16, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 10],
|
||||
'Q' => ['group1_blocks' => 1, 'group1_data_per_block' => 13, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 13],
|
||||
'H' => ['group1_blocks' => 1, 'group1_data_per_block' => 9, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 17],
|
||||
],
|
||||
2 => [
|
||||
'L' => ['group1_blocks' => 1, 'group1_data_per_block' => 34, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 10],
|
||||
'M' => ['group1_blocks' => 1, 'group1_data_per_block' => 28, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 16],
|
||||
'Q' => ['group1_blocks' => 1, 'group1_data_per_block' => 22, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 22],
|
||||
'H' => ['group1_blocks' => 1, 'group1_data_per_block' => 16, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 28],
|
||||
],
|
||||
3 => [
|
||||
'L' => ['group1_blocks' => 1, 'group1_data_per_block' => 55, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 15],
|
||||
'M' => ['group1_blocks' => 1, 'group1_data_per_block' => 44, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 26],
|
||||
'Q' => ['group1_blocks' => 2, 'group1_data_per_block' => 17, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 18],
|
||||
'H' => ['group1_blocks' => 2, 'group1_data_per_block' => 13, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 22],
|
||||
],
|
||||
4 => [
|
||||
'L' => ['group1_blocks' => 1, 'group1_data_per_block' => 80, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 20],
|
||||
'M' => ['group1_blocks' => 2, 'group1_data_per_block' => 32, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 18],
|
||||
'Q' => ['group1_blocks' => 2, 'group1_data_per_block' => 24, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 26],
|
||||
'H' => ['group1_blocks' => 4, 'group1_data_per_block' => 9, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 16],
|
||||
],
|
||||
5 => [
|
||||
'L' => ['group1_blocks' => 1, 'group1_data_per_block' => 108, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 26],
|
||||
'M' => ['group1_blocks' => 2, 'group1_data_per_block' => 43, 'group2_blocks' => 0, 'group2_data_per_block' => 0, 'error_correction_per_block' => 24],
|
||||
'Q' => ['group1_blocks' => 2, 'group1_data_per_block' => 15, 'group2_blocks' => 2, 'group2_data_per_block' => 16, 'error_correction_per_block' => 18],
|
||||
'H' => ['group1_blocks' => 2, 'group1_data_per_block' => 11, 'group2_blocks' => 2, 'group2_data_per_block' => 12, 'error_correction_per_block' => 22],
|
||||
],
|
||||
];
|
||||
|
||||
if (! isset($blockStructures[$version][$errorLevel])) {
|
||||
// Default fallback for unsupported versions
|
||||
return [
|
||||
'group1_blocks' => 1,
|
||||
'group1_data_per_block' => ReedSolomonEncoder::getDataCapacity($version, $errorLevel),
|
||||
'group2_blocks' => 0,
|
||||
'group2_data_per_block' => 0,
|
||||
'error_correction_per_block' => ReedSolomonEncoder::getErrorCorrectionCodewords($version, $errorLevel),
|
||||
];
|
||||
}
|
||||
|
||||
return $blockStructures[$version][$errorLevel];
|
||||
}
|
||||
}
|
||||
43
src/Framework/QrCode/Structure/QrCodeBlock.php
Normal file
43
src/Framework/QrCode/Structure/QrCodeBlock.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\QrCode\Structure;
|
||||
|
||||
/**
|
||||
* QR Code Data Block
|
||||
*
|
||||
* Represents a single data block with error correction codewords
|
||||
*/
|
||||
final readonly class QrCodeBlock
|
||||
{
|
||||
public function __construct(
|
||||
public array $dataCodewords,
|
||||
public array $errorCorrectionCodewords
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total codewords (data + error correction)
|
||||
*/
|
||||
public function getTotalCodewords(): array
|
||||
{
|
||||
return array_merge($this->dataCodewords, $this->errorCorrectionCodewords);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of data codewords
|
||||
*/
|
||||
public function getDataLength(): int
|
||||
{
|
||||
return count($this->dataCodewords);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of error correction codewords
|
||||
*/
|
||||
public function getErrorCorrectionLength(): int
|
||||
{
|
||||
return count($this->errorCorrectionCodewords);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user