Skip to content

Commit 39b3d0c

Browse files
authored
feature: add QxManager sample sheet (#8)
* feature: add `QxManager` sample sheet
1 parent f27c90f commit 39b3d0c

11 files changed

+451
-1
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+
## v1.7.0
13+
14+
### Added
15+
16+
- Add `QxManagerSampleSheet::toCsvString(...)`
17+
1218
## v1.6.1
1319

1420
### Fixed

composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"require": {
1818
"php": "^7.4 || ^8",
1919
"illuminate/support": "^8.73 || ^9 || ^10",
20+
"mll-lab/microplate": "^6",
2021
"mll-lab/str_putcsv": "^1",
2122
"thecodingmachine/safe": "^1 || ^2"
2223
},
@@ -25,6 +26,7 @@
2526
"infection/infection": "^0.26 || ^0.27",
2627
"jangregor/phpstan-prophecy": "^1",
2728
"mll-lab/php-cs-fixer-config": "^5",
29+
"nesbot/carbon": "^2.62.1",
2830
"phpstan/extension-installer": "^1",
2931
"phpstan/phpstan": "^1",
3032
"phpstan/phpstan-deprecation-rules": "^1",

src/QxManager/EmptyRow.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\QxManager;
4+
5+
class EmptyRow
6+
{
7+
public function toString(): string
8+
{
9+
return implode(QxManagerSampleSheet::DELIMITER, [
10+
'No',
11+
...array_fill(0, 16, null),
12+
]);
13+
}
14+
}

src/QxManager/FilledRow.php

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\QxManager;
4+
5+
class FilledRow
6+
{
7+
private string $experimentType;
8+
9+
private string $supermixName;
10+
11+
private string $assayType;
12+
13+
private string $targetType;
14+
15+
private string $plot;
16+
17+
private string $targetName;
18+
19+
private string $signalCh1;
20+
21+
private string $signalCh2;
22+
23+
private string $sampleDescription1;
24+
25+
private ?string $sampleDescription2;
26+
27+
private ?string $sampleDescription3;
28+
29+
private ?string $sampleDescription4;
30+
31+
private string $sampleType;
32+
33+
private ?int $referenceCopies;
34+
35+
private ?string $wellNotes;
36+
37+
private ?string $rdqConversionFactor;
38+
39+
public function __construct(
40+
string $sampleDescription1,
41+
?string $sampleDescription2,
42+
?string $sampleDescription3,
43+
?string $sampleDescription4,
44+
string $sampleType,
45+
string $experimentType,
46+
string $supermixName,
47+
string $assayType,
48+
string $targetType,
49+
string $plot,
50+
string $targetName,
51+
string $signalCh1,
52+
string $signalCh2,
53+
int $referenceCopies = null,
54+
string $wellNotes = null,
55+
string $rdqConversionFactor = null
56+
) {
57+
$this->targetName = $targetName;
58+
$this->signalCh1 = $signalCh1;
59+
$this->signalCh2 = $signalCh2;
60+
$this->sampleDescription1 = $sampleDescription1;
61+
$this->sampleDescription2 = $sampleDescription2;
62+
$this->sampleDescription3 = $sampleDescription3;
63+
$this->sampleDescription4 = $sampleDescription4;
64+
$this->sampleType = $sampleType;
65+
$this->experimentType = $experimentType;
66+
$this->supermixName = $supermixName;
67+
$this->assayType = $assayType;
68+
$this->targetType = $targetType;
69+
$this->plot = $plot;
70+
$this->referenceCopies = $referenceCopies;
71+
$this->wellNotes = $wellNotes;
72+
$this->rdqConversionFactor = $rdqConversionFactor;
73+
}
74+
75+
public function toString(): string
76+
{
77+
return implode(QxManagerSampleSheet::DELIMITER, [
78+
'Yes',
79+
$this->experimentType,
80+
$this->sampleDescription1,
81+
$this->sampleDescription2,
82+
$this->sampleDescription3,
83+
$this->sampleDescription4,
84+
$this->sampleType,
85+
$this->supermixName,
86+
$this->assayType,
87+
$this->targetName,
88+
$this->targetType,
89+
$this->signalCh1,
90+
$this->signalCh2,
91+
$this->referenceCopies,
92+
$this->wellNotes,
93+
$this->plot,
94+
$this->rdqConversionFactor,
95+
]);
96+
}
97+
}

src/QxManager/FilledWell.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\QxManager;
4+
5+
use Mll\Microplate\Coordinates;
6+
use Mll\Microplate\CoordinateSystem96Well;
7+
8+
class FilledWell
9+
{
10+
private FilledRow $famRow;
11+
12+
private FilledRow $hexRow;
13+
14+
public function __construct(FilledRow $famRow, FilledRow $hexRow)
15+
{
16+
$this->famRow = $famRow;
17+
$this->hexRow = $hexRow;
18+
}
19+
20+
/** @param Coordinates<CoordinateSystem96Well> $coordinates */
21+
public function toString(Coordinates $coordinates): string
22+
{
23+
return $coordinates->toPaddedString() . QxManagerSampleSheet::DELIMITER . $this->famRow->toString() . QxManagerSampleSheet::EOL
24+
. $coordinates->toPaddedString() . QxManagerSampleSheet::DELIMITER . $this->hexRow->toString();
25+
}
26+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\QxManager;
4+
5+
use Carbon\CarbonInterface;
6+
use Mll\Microplate\Coordinates;
7+
use Mll\Microplate\CoordinateSystem96Well;
8+
use Mll\Microplate\Enums\FlowDirection;
9+
use Mll\Microplate\Microplate;
10+
use MLL\Utils\StringUtil;
11+
12+
class QxManagerSampleSheet
13+
{
14+
public const EOL = "\r\n";
15+
public const DELIMITER = ',';
16+
17+
/** @param Microplate<FilledWell, CoordinateSystem96Well> $microplate */
18+
public function toCsvString(Microplate $microplate, CarbonInterface $createdDate): string
19+
{
20+
$header = StringUtil::normalizeLineEndings(
21+
<<<CSV
22+
ddplate - DO NOT MODIFY THIS LINE,Version=1,ApplicationName=QX Manager Standard Edition,ApplicationVersion=2.0.0.665,ApplicationEdition=ResearchEmbedded,User=\QX User,CreatedDate={$createdDate->format('n/j/Y g:i:s A')},
23+
24+
PlateSize=GCR96
25+
PlateNotes=
26+
Well,Perform Droplet Reading,ExperimentType,Sample description 1,Sample description 2,Sample description 3,Sample description 4,SampleType,SupermixName,AssayType,TargetName,TargetType,Signal Ch1,Signal Ch2,Reference Copies,Well Notes,Plot?,RdqConversionFactor
27+
28+
CSV
29+
);
30+
31+
return $header . $microplate->sortedWells(FlowDirection::ROW())
32+
->map(
33+
/** @param FilledWell|null $well */
34+
function ($well, string $coordinateString) use ($microplate): string {
35+
$coordinates = Coordinates::fromString($coordinateString, $microplate->coordinateSystem);
36+
37+
if ($well instanceof FilledWell) {
38+
return $well->toString($coordinates);
39+
}
40+
41+
return $coordinates->toPaddedString() . QxManagerSampleSheet::DELIMITER . (new EmptyRow())->toString();
42+
}
43+
)
44+
->join(self::EOL) . self::EOL;
45+
}
46+
}

tests/CSVArrayTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php declare(strict_types=1);
22

3-
namespace MLL\Utils\Tests\Unit;
3+
namespace MLL\Utils\Tests;
44

55
use MLL\Utils\CSVArray;
66
use PHPUnit\Framework\TestCase;

tests/QxManager/EmptyRowTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\Tests\QxManager;
4+
5+
use MLL\Utils\QxManager\EmptyRow;
6+
use PHPUnit\Framework\TestCase;
7+
8+
final class EmptyRowTest extends TestCase
9+
{
10+
public function testToString(): void
11+
{
12+
self::assertSame('No,,,,,,,,,,,,,,,,', (new EmptyRow())->toString());
13+
}
14+
}

tests/QxManager/FilledRowTest.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\Tests\Unit\QxManager;
4+
5+
use MLL\Utils\QxManager\FilledRow;
6+
use PHPUnit\Framework\TestCase;
7+
8+
final class FilledRowTest extends TestCase
9+
{
10+
public function testToString(): void
11+
{
12+
$filledRow = new FilledRow(
13+
'Sample 1',
14+
'Sample 2',
15+
null,
16+
null,
17+
'Sample Type',
18+
'Experiment Type',
19+
'Supermix Name',
20+
'Assay Type',
21+
'Target Type',
22+
'Plot',
23+
'Target Name',
24+
'Signal Ch1',
25+
'Signal Ch2',
26+
1000,
27+
'Well Notes',
28+
'RDQ Conversion Factor'
29+
);
30+
31+
$expectedString = 'Yes,Experiment Type,Sample 1,Sample 2,,,Sample Type,Supermix Name,Assay Type,Target Name,Target Type,Signal Ch1,Signal Ch2,1000,Well Notes,Plot,RDQ Conversion Factor';
32+
33+
self::assertSame($expectedString, $filledRow->toString());
34+
}
35+
36+
public function testToStringWithNullValues(): void
37+
{
38+
$filledRow = new FilledRow(
39+
'Sample 1',
40+
null,
41+
null,
42+
null,
43+
'Sample Type',
44+
'Experiment Type',
45+
'Supermix Name',
46+
'Assay Type',
47+
'Target Type',
48+
'Plot',
49+
'Target Name',
50+
'Signal Ch1',
51+
'Signal Ch2'
52+
);
53+
54+
$expectedString = 'Yes,Experiment Type,Sample 1,,,,Sample Type,Supermix Name,Assay Type,Target Name,Target Type,Signal Ch1,Signal Ch2,,,Plot,';
55+
56+
self::assertSame($expectedString, $filledRow->toString());
57+
}
58+
}

tests/QxManager/FilledWellTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\Utils\Tests\Unit\QxManager;
4+
5+
use Mll\Microplate\Coordinates;
6+
use Mll\Microplate\CoordinateSystem96Well;
7+
use MLL\Utils\QxManager\FilledRow;
8+
use MLL\Utils\QxManager\FilledWell;
9+
use PHPUnit\Framework\TestCase;
10+
11+
final class FilledWellTest extends TestCase
12+
{
13+
public function testToString(): void
14+
{
15+
$coordinates = Coordinates::fromString('C9', new CoordinateSystem96Well());
16+
17+
$famRowMock = $this->createMock(FilledRow::class);
18+
$famRowMock->expects(self::once())
19+
->method('toString')
20+
->willReturn('FAM Row String');
21+
22+
$hexRowMock = $this->createMock(FilledRow::class);
23+
$hexRowMock->expects(self::once())
24+
->method('toString')
25+
->willReturn('HEX Row String');
26+
27+
$filledWell = new FilledWell($famRowMock, $hexRowMock);
28+
29+
self::assertSame("C09,FAM Row String\r\nC09,HEX Row String", $filledWell->toString($coordinates));
30+
}
31+
}

0 commit comments

Comments
 (0)