From 715a8707fd743d194734be6c7b10ecd72faa3cf5 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 25 Sep 2026 05:20:59 +0200 Subject: [PATCH 1/2] Fix remaining PHPStan errors, drop the baseline --- .../Controllers/Crud/ObjectsController.php | 6 ++-- .../Controllers/PdfController.php | 1 - lib/GaletteObjectsLend/IO/PdfObjects.php | 33 ++++++++----------- phpstan-baseline.neon | 31 ----------------- phpstan.neon | 3 -- 5 files changed, 17 insertions(+), 57 deletions(-) delete mode 100644 phpstan-baseline.neon diff --git a/lib/GaletteObjectsLend/Controllers/Crud/ObjectsController.php b/lib/GaletteObjectsLend/Controllers/Crud/ObjectsController.php index 78f472f..cee752e 100644 --- a/lib/GaletteObjectsLend/Controllers/Crud/ObjectsController.php +++ b/lib/GaletteObjectsLend/Controllers/Crud/ObjectsController.php @@ -509,7 +509,7 @@ public function doUpdateStatus(Request $request, Response $response, ?int $id = ->withStatus(301) ->withHeader( 'Location', - $this->routeparser->urlFor('objectslend_object_edit', ['id' => $object->getId()]) + $this->routeparser->urlFor('objectslend_object_edit', ['id' => (string)$object->getId()]) ); } @@ -579,7 +579,7 @@ public function doClone(Request $request, Response $response, int $id): Response 'Location', $this->routeparser->urlFor( 'objectslend_object_edit', - ['id' => $object->getId()] + ['id' => (string)$object->getId()] ) ); } @@ -902,7 +902,7 @@ public function confirmRemoveTitle(array $args): string $filters = $this->getFilters(); return str_replace( '%count', - count($filters->selected), + (string)count($filters->selected), _T('You are about to remove %count objects.', 'objectslend') ); } diff --git a/lib/GaletteObjectsLend/Controllers/PdfController.php b/lib/GaletteObjectsLend/Controllers/PdfController.php index d835a8a..046fffa 100644 --- a/lib/GaletteObjectsLend/Controllers/PdfController.php +++ b/lib/GaletteObjectsLend/Controllers/PdfController.php @@ -72,7 +72,6 @@ public function printObjects(Request $request, Response $response): Response $this->zdb, $this->preferences, $lendsprefs, - $filters, $this->login ); diff --git a/lib/GaletteObjectsLend/IO/PdfObjects.php b/lib/GaletteObjectsLend/IO/PdfObjects.php index df1fbb5..ab740b9 100644 --- a/lib/GaletteObjectsLend/IO/PdfObjects.php +++ b/lib/GaletteObjectsLend/IO/PdfObjects.php @@ -16,7 +16,6 @@ use Galette\Core\Preferences; use Galette\Core\Login; use GaletteObjectsLend\Entity\LendObject; -use GaletteObjectsLend\Filters\ObjectsList; use GaletteObjectsLend\Entity\LendCategory; use GaletteObjectsLend\LendPreferences; @@ -31,7 +30,6 @@ class PdfObjects extends Pdf private Db $zdb; private LendPreferences $lendsprefs; - private ObjectsList $filters; private Login $login; /** @@ -40,14 +38,12 @@ class PdfObjects extends Pdf * @param Db $zdb Database instance * @param Preferences $prefs Preferences * @param LendPreferences $lendsprefs Plugin preferences - * @param ObjectsList $filters Current filters * @param Login $login Login instance */ public function __construct( Db $zdb, Preferences $prefs, LendPreferences $lendsprefs, - ObjectsList $filters, Login $login, ) { parent::__construct($prefs); @@ -58,7 +54,6 @@ public function __construct( $this->filename = _T('objects_cards', 'objectslend') . '.pdf'; $this->zdb = $zdb; $this->lendsprefs = $lendsprefs; - $this->filters = $filters; $this->login = $login; } @@ -91,7 +86,7 @@ public function Header(): void // @phpcs:enable $this->SetFont(Pdf::FONT, 'B'); $x = $this->getX(); - $this->Cell(0, 10, _T("Objects list", "objectslend"), 0, false, 'C', false, '', 0, false, 'M', 'M'); + $this->Cell(0, 10, _T("Objects list", "objectslend"), 0, 0, 'C', false, '', 0, false, 'M', 'M'); $this->SetFont(Pdf::FONT, '', self::LIST_FONT); $this->setX($x); $this->Cell( @@ -103,7 +98,7 @@ public function Header(): void _T("Printed on %date", "objectslend") ), 0, - false, + 0, 'R', false, '', @@ -137,18 +132,18 @@ public function drawList(array $objects): void $w_date = 22; $w_adherent = 26; - $this->Cell($w_checkbox, 0, $this->stretchHead('', $w_checkbox), 1, 0, 'C', 1); - $this->Cell($w_name, 0, $this->stretchHead(_T("Name", "objectslend"), $w_name), 1, 0, 'C', 1); - $this->Cell($w_description, 0, $this->stretchHead(_T("Description", "objectslend"), $w_description), 1, 0, 'C', 1); - $this->Cell($w_serial, 0, $this->stretchHead(_T("Serial", "objectslend"), $w_serial), 1, 0, 'C', 1); - $this->Cell($w_price, 0, $this->stretchHead(_T("Price", "objectslend"), $w_price), 1, 0, 'C', 1); - $this->Cell($w_price, 0, $this->stretchHead(_T("Borrow price", "objectslend"), $w_price), 1, 0, 'C', 1); - $this->Cell($w_dimension, 0, $this->stretchHead(_T("Dimensions", "objectslend"), $w_dimension), 1, 0, 'C', 1); - $this->Cell($w_weight, 0, $this->stretchHead(_T("Weight", "objectslend"), $w_weight), 1, 0, 'C', 1); - $this->Cell($w_status, 0, $this->stretchHead(_T("Status", "objectslend"), $w_status), 1, 0, 'C', 1); - $this->Cell($w_date, 0, $this->stretchHead(_T("Since", "objectslend"), $w_date), 1, 0, 'C', 1); - $this->Cell($w_adherent, 0, $this->stretchHead(_T("Member", "objectslend"), $w_adherent), 1, 0, 'C', 1); - $this->Cell($w_date, 0, $this->stretchHead(_T("Return", "objectslend"), $w_date), 1, 1, 'C', 1); + $this->Cell($w_checkbox, 0, $this->stretchHead('', $w_checkbox), 1, 0, 'C', true); + $this->Cell($w_name, 0, $this->stretchHead(_T("Name", "objectslend"), $w_name), 1, 0, 'C', true); + $this->Cell($w_description, 0, $this->stretchHead(_T("Description", "objectslend"), $w_description), 1, 0, 'C', true); + $this->Cell($w_serial, 0, $this->stretchHead(_T("Serial", "objectslend"), $w_serial), 1, 0, 'C', true); + $this->Cell($w_price, 0, $this->stretchHead(_T("Price", "objectslend"), $w_price), 1, 0, 'C', true); + $this->Cell($w_price, 0, $this->stretchHead(_T("Borrow price", "objectslend"), $w_price), 1, 0, 'C', true); + $this->Cell($w_dimension, 0, $this->stretchHead(_T("Dimensions", "objectslend"), $w_dimension), 1, 0, 'C', true); + $this->Cell($w_weight, 0, $this->stretchHead(_T("Weight", "objectslend"), $w_weight), 1, 0, 'C', true); + $this->Cell($w_status, 0, $this->stretchHead(_T("Status", "objectslend"), $w_status), 1, 0, 'C', true); + $this->Cell($w_date, 0, $this->stretchHead(_T("Since", "objectslend"), $w_date), 1, 0, 'C', true); + $this->Cell($w_adherent, 0, $this->stretchHead(_T("Member", "objectslend"), $w_adherent), 1, 0, 'C', true); + $this->Cell($w_date, 0, $this->stretchHead(_T("Return", "objectslend"), $w_date), 1, 1, 'C', true); $this->SetFont(''); diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon deleted file mode 100644 index c2e8d3d..0000000 --- a/phpstan-baseline.neon +++ /dev/null @@ -1,31 +0,0 @@ -parameters: - ignoreErrors: - - - message: '#^Parameter \#2 \$data of method Slim\\Routing\\RouteParser\:\:urlFor\(\) expects array\, array\ given\.$#' - identifier: argument.type - count: 2 - path: lib/GaletteObjectsLend/Controllers/Crud/ObjectsController.php - - - - message: '#^Parameter \#2 \$replace of function str_replace expects array\\|string, int\<0, max\> given\.$#' - identifier: argument.type - count: 1 - path: lib/GaletteObjectsLend/Controllers/Crud/ObjectsController.php - - - - message: '#^Parameter \#5 \$ln of method TCPDF\:\:Cell\(\) expects int, false given\.$#' - identifier: argument.type - count: 2 - path: lib/GaletteObjectsLend/IO/PdfObjects.php - - - - message: '#^Parameter \#7 \$fill of method TCPDF\:\:Cell\(\) expects bool, int given\.$#' - identifier: argument.type - count: 12 - path: lib/GaletteObjectsLend/IO/PdfObjects.php - - - - message: '#^Property GaletteObjectsLend\\IO\\PdfObjects\:\:\$filters is never read, only written\.$#' - identifier: property.onlyWritten - count: 1 - path: lib/GaletteObjectsLend/IO/PdfObjects.php diff --git a/phpstan.neon b/phpstan.neon index 1be09ea..d2d1bae 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,6 +1,3 @@ -includes: - - phpstan-baseline.neon - parameters: parallel: maximumNumberOfProcesses: 2 From ae5a3f311096866fc0feaf65f7d1c9e7be67cd80 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 25 Sep 2026 05:20:59 +0200 Subject: [PATCH 2/2] Track current category in objects list PDF, never mix homonymous categories --- lib/GaletteObjectsLend/IO/PdfObjects.php | 23 ++++++----- lib/GaletteObjectsLend/Repository/Objects.php | 3 +- .../Repository/tests/units/Objects.php | 39 +++++++++++++++++++ 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/lib/GaletteObjectsLend/IO/PdfObjects.php b/lib/GaletteObjectsLend/IO/PdfObjects.php index ab740b9..99de8d5 100644 --- a/lib/GaletteObjectsLend/IO/PdfObjects.php +++ b/lib/GaletteObjectsLend/IO/PdfObjects.php @@ -147,41 +147,40 @@ public function drawList(array $objects): void $this->SetFont(''); - $current_category = -1; + //objects come ordered by category: a heading, and the previous + //category subtotal, each time it changes + $current_category = null; $sum_price = 0; $grant_total = 0; $row = 0; - $existing_categories = []; foreach ($objects as $object) { + $category_id = (int)$object->getCategoryId(); if ( $this->lendsprefs->isEnabled(LendPreferences::VIEW_CATEGORY) - && $current_category !== $object->getCategoryId() + && $current_category !== $category_id ) { $this->SetFont('', 'B'); - if (($this->login->isAdmin() || $this->login->isStaff()) && $sum_price > 0 && !in_array($object->getCategoryId(), $existing_categories)) { + if (($this->login->isAdmin() || $this->login->isStaff()) && $sum_price > 0) { $width = $w_checkbox + $w_name + $w_description + $w_serial + $w_price; $this->Cell($width, 0, number_format($sum_price, 2, ',', ''), '', 0, 'R'); $sum_price = 0; $this->Ln(); } - if (!empty($object->getCategoryId()) && !in_array($object->getCategoryId(), $existing_categories)) { - $category = new LendCategory($this->zdb, (int)$object->getCategoryId()); + if ($category_id > 0) { + $category = new LendCategory($this->zdb, $category_id); $text = str_replace( '%category', $category->getName(false), _T("Category: %category", "objectslend") ); - $existing_categories[] = $object->getCategoryId(); - $this->Cell(0, 0, $text, 0, 1, 'C'); - } elseif (!in_array(0, $existing_categories)) { + } else { $text = _T("No category", "objectslend"); - $existing_categories[0] = 0; - $this->Cell(0, 0, $text, 0, 1, 'C'); } - + $this->Cell(0, 0, $text, 0, 1, 'C'); + $current_category = $category_id; $this->SetFont(''); } diff --git a/lib/GaletteObjectsLend/Repository/Objects.php b/lib/GaletteObjectsLend/Repository/Objects.php index c7d8c7d..f90f0c2 100644 --- a/lib/GaletteObjectsLend/Repository/Objects.php +++ b/lib/GaletteObjectsLend/Repository/Objects.php @@ -233,7 +233,8 @@ protected function buildOrderClause(): array self::ORDERBY_BDATE => ['r.date_begin'], self::ORDERBY_FDATE => ['r.date_forecast'], self::ORDERBY_MEMBER => ['a.nom_adh', 'a.prenom_adh'], - self::ORDERBY_CATEGORY => ['c.name'], + //homonymous categories must not be mixed: the objects list PDF relies on it + self::ORDERBY_CATEGORY => ['c.name', 'o.category_id'], default => [] }; diff --git a/tests/GaletteObjectsLend/Repository/tests/units/Objects.php b/tests/GaletteObjectsLend/Repository/tests/units/Objects.php index 5bd2fb7..b5fb88b 100644 --- a/tests/GaletteObjectsLend/Repository/tests/units/Objects.php +++ b/tests/GaletteObjectsLend/Repository/tests/units/Objects.php @@ -222,4 +222,43 @@ public function testGetList(): void $objects->removeObjects([$first_object_id, $second_object_id, $third_object_id]); $this->assertCount(1, $objects->getObjectsList(true)); } + + /** + * Objects of homonymous categories are not mixed when ordered by category + */ + public function testOrderByHomonymousCategories(): void + { + $category_ids = []; + foreach ([1, 2] as $i) { + $category = new \GaletteObjectsLend\Entity\LendCategory($this->zdb); + $category->setName('Same name'); + $category->setActive(true); + $category->store(); + $category_ids[] = $category->getId(); + } + + //stored alternately, so that an order on the name alone may mix them + foreach ([0, 1, 0, 1, 0, 1] as $i => $index) { + $object = new \GaletteObjectsLend\Entity\LendObject($this->zdb); + $object->setName('Object ' . $i); + $object->setCategoryId($category_ids[$index]); + $object->setActive(true); + $object->store(); + } + + $filters = new \GaletteObjectsLend\Filters\ObjectsList(); + $filters->orderby = \GaletteObjectsLend\Repository\Objects::ORDERBY_CATEGORY; + $objects = new \GaletteObjectsLend\Repository\Objects($this->zdb, $this->preferences, $this->login, $this->lend_prefs, $filters); + $list = $objects->getObjectsList(true, true, false); + $this->assertCount(6, $list); + + $sequence = array_map(fn($object) => $object->getCategoryId(), $list); + $changes = 0; + for ($i = 1; $i < count($sequence); $i++) { + if ($sequence[$i] !== $sequence[$i - 1]) { + $changes++; + } + } + $this->assertSame(1, $changes, 'Categories order: ' . implode(', ', $sequence)); + } }