Skip to content

Commit f279248

Browse files
authored
Lightcycler sample sheet
1 parent ed76cb1 commit f279248

File tree

6 files changed

+174
-0
lines changed

6 files changed

+174
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ See [GitHub releases](https://github.com/mll-lab/php-utils/releases).
99

1010
## Unreleased
1111

12+
## v5.10.0
13+
14+
### Added
15+
16+
- Support creating Lightcycler Sample Sheets for Relative Quantification
17+
1218
## v5.9.0
1319

1420
### Added
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\LightcyclerSampleSheet;
4+
5+
class RandomHexGenerator
6+
{
7+
/** @var list<string> */
8+
private array $generatedHexCodes = [];
9+
10+
public function uniqueHex6Digits(): string
11+
{
12+
do {
13+
$randomNumber = mt_rand(0, 0xFFFFFF);
14+
$hexString = dechex($randomNumber);
15+
$paddedHexString = str_pad($hexString, 6, '0', STR_PAD_LEFT);
16+
$uniqueHexCode = strtoupper($paddedHexString);
17+
} while (in_array($uniqueHexCode, $this->generatedHexCodes, true));
18+
19+
$this->generatedHexCodes[] = $uniqueHexCode;
20+
21+
return $uniqueHexCode;
22+
}
23+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\LightcyclerSampleSheet;
4+
5+
use MLL\Utils\Microplate\Coordinates;
6+
use MLL\Utils\Microplate\CoordinateSystem12x8;
7+
8+
class RelativeQuantificationSample
9+
{
10+
public string $sampleName;
11+
12+
public string $filterCombination;
13+
14+
public string $hexColor;
15+
16+
/** @var Coordinates<CoordinateSystem12x8>|null */
17+
public ?Coordinates $replicationOf;
18+
19+
/** @param Coordinates<CoordinateSystem12x8>|null $replicationOf */
20+
public function __construct(
21+
string $sampleName,
22+
string $filterCombination,
23+
string $hexColor,
24+
?Coordinates $replicationOf
25+
) {
26+
$this->sampleName = $sampleName;
27+
$this->filterCombination = $filterCombination;
28+
$this->hexColor = $hexColor;
29+
$this->replicationOf = $replicationOf;
30+
}
31+
32+
/** @return list<string> */
33+
public function toSerializableArray(string $coordinatesString): array
34+
{
35+
$replicationOf = $this->replicationOf instanceof Coordinates
36+
? "\"{$this->replicationOf->toString()}\""
37+
: '""';
38+
39+
return [
40+
Coordinates::fromString($coordinatesString, new CoordinateSystem12x8())->toString(),
41+
"\"{$this->sampleName}\"",
42+
$replicationOf,
43+
$this->filterCombination,
44+
"$00{$this->hexColor}",
45+
];
46+
}
47+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\LightcyclerSampleSheet;
4+
5+
use Illuminate\Support\Collection;
6+
7+
class RelativeQuantificationSheet
8+
{
9+
protected const WINDOWS_NEW_LINE = "\r\n";
10+
protected const TAB_SEPARATOR = "\t";
11+
public const HEADER_COLUMNS = [
12+
'"General:Pos"',
13+
'"General:Sample Name"',
14+
'"General:Repl. Of"',
15+
'"General:Filt. Comb."',
16+
'"Sample Preferences:Color"',
17+
];
18+
19+
/** @param Collection<string, RelativeQuantificationSample> $samples */
20+
public function generate(Collection $samples): string
21+
{
22+
return $samples
23+
->map(fn (RelativeQuantificationSample $well, string $coordinateFromKey): array => $well->toSerializableArray($coordinateFromKey))
24+
->prepend(self::HEADER_COLUMNS)
25+
->map(fn (array $row): string => implode(self::TAB_SEPARATOR, $row))
26+
->implode(self::WINDOWS_NEW_LINE)
27+
. self::WINDOWS_NEW_LINE;
28+
}
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\Tests\LightcyclerSampleSheet;
4+
5+
use MLL\Utils\LightcyclerSampleSheet\RandomHexGenerator;
6+
use PHPUnit\Framework\TestCase;
7+
8+
final class RandomHexGeneratorTest extends TestCase
9+
{
10+
public function testGeneratesValidHexCode(): void
11+
{
12+
$generator = new RandomHexGenerator();
13+
$hexCode = $generator->uniqueHex6Digits();
14+
15+
self::assertTrue((bool) \Safe\preg_match('/^[A-F0-9]{6}$/', $hexCode));
16+
}
17+
18+
public function testGeneratesUniqueHexCodes(): void
19+
{
20+
$generator = new RandomHexGenerator();
21+
$hexCodes = [];
22+
23+
for ($i = 0; $i < 1000; ++$i) {
24+
$hexCodes[] = $generator->uniqueHex6Digits();
25+
}
26+
27+
self::assertCount(1000, array_unique($hexCodes));
28+
}
29+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\Tests\LightcyclerSampleSheet;
4+
5+
use Illuminate\Support\Collection;
6+
use MLL\Utils\LightcyclerSampleSheet\RelativeQuantificationSample;
7+
use MLL\Utils\LightcyclerSampleSheet\RelativeQuantificationSheet;
8+
use MLL\Utils\Microplate\Coordinates;
9+
use MLL\Utils\Microplate\CoordinateSystem12x8;
10+
use MLL\Utils\StringUtil;
11+
use PHPUnit\Framework\TestCase;
12+
13+
final class RelativeQuantificationSheetTest extends TestCase
14+
{
15+
public function testGenerate(): void
16+
{
17+
$samples = Collection::make([
18+
'A1' => new RelativeQuantificationSample('Sample 1', '498-640', 'FF378A', null),
19+
'B1' => new RelativeQuantificationSample('Sample 2', '498-640', '4899D1', null),
20+
'C1' => new RelativeQuantificationSample('Sample 3', '498-640', '8528B9', null),
21+
'D1' => new RelativeQuantificationSample('Sample 4', '498-640', '8E05D9', null),
22+
'E1' => new RelativeQuantificationSample('Sample 5', '498-640', '4080A5', Coordinates::fromString('C12', new CoordinateSystem12x8())),
23+
]);
24+
25+
$sheet = new RelativeQuantificationSheet();
26+
$result = $sheet->generate($samples);
27+
28+
$expected = <<<EOT
29+
"General:Pos"\t"General:Sample Name"\t"General:Repl. Of"\t"General:Filt. Comb."\t"Sample Preferences:Color"
30+
A1\t"Sample 1"\t""\t498-640\t$00FF378A
31+
B1\t"Sample 2"\t""\t498-640\t$004899D1
32+
C1\t"Sample 3"\t""\t498-640\t$008528B9
33+
D1\t"Sample 4"\t""\t498-640\t$008E05D9
34+
E1\t"Sample 5"\t"C12"\t498-640\t$004080A5
35+
36+
EOT;
37+
38+
self::assertSame(StringUtil::normalizeLineEndings($expected), $result);
39+
}
40+
}

0 commit comments

Comments
 (0)