levelmax World 6 Errors & Edges
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. B
L
Level 6.B ~25 min Target: PHPStan max

Boss: a supplier price import

The tea supplier uploaded a price list of 112 products and was told Imported 40 products. Six rows had been skipped, each with a line in a log nobody reads. Loose Earl Grey at £0.29 went into the catalogue at 28p. And on row 47 the database timed out, which the import caught, logged as one more bad row, and carried on from. Nobody can say which 40 got in.

ProductImport::run() is twenty lines long, and every one of World 6's mistakes is in it.

Your checklist

Level Ask of ProductImport
6.1 Exceptions with names Does it react to failures by their type, like InvalidSku, and never by reading a message?
6.2 Never swallow Does every catch name the one failure it handles, around only the call that throws it?
6.3 Failure in the signature Does @throws say what reaches the controller, and does PHPStan agree?
6.4 Validation isn't exceptional Does a bad file come back as ImportProblems with every bad line, not just the first?
6.5 Leave it as you found it If anything fails, is the catalogue exactly as it was before the upload?

Floats are back for one last appearance, too. (float) '0.29' * 100 is 28.999999999999996, and (int) rounds it down. 5.2 said what to do about money, and it still applies when the money arrives as text.

CHALLENGE

Suppliers upload their price lists as CSV. Last week's from the tea supplier imported 29p loose Earl Grey at 28p, skipped six rows nobody was told about, and then hit a database timeout half-way through, which was logged as one more bad row. The supplier got Imported 40 products for a file of 112.

Rebuild src/ProductImport.php so the tests pass and PHPStan is clean, with checked exceptions on. ImportController (read only) is already written against the result:

  • run() returns Imported, or ImportProblems listing every bad line by its line number, including the headings line if it isn't sku,name,price
  • if any line has a problem, nothing is imported: the supplier will fix the file and upload all of it again
  • prices are exact pence, from pounds and pence like 12.50, and must be more than nothing
  • the same SKU twice in one file is a problem on the later line
  • a CatalogueUnavailable reaches the controller, declared in @throws, and anything else that goes wrong isn't reported as a bad line
Running on PHP 8.3…

Run the tests, run PHPStan, or submit for both. Ctrl/⌘ + Enter submits from the editor.