diff --git a/examples/create_shapefile.php b/examples/create_shapefile.php index 59f0f71..f3ec850 100644 --- a/examples/create_shapefile.php +++ b/examples/create_shapefile.php @@ -25,29 +25,30 @@ use PhpMyAdmin\ShapeFile\ShapeFile; use PhpMyAdmin\ShapeFile\ShapeRecord; +use PhpMyAdmin\ShapeFile\ShapeType; require_once __DIR__ . '/../vendor/autoload.php'; -$shp = new ShapeFile(1, [ +$shp = new ShapeFile(ShapeType::POINT, [ 'xmin' => 464079.002268, 'ymin' => 2120153.74792, 'xmax' => 505213.52849, 'ymax' => 2163205.70036, ]); -$record0 = new ShapeRecord(1); +$record0 = new ShapeRecord(ShapeType::POINT); $record0->addPoint([ 'x' => 482131.764567, 'y' => 2143634.39608, ]); -$record1 = new ShapeRecord(1); +$record1 = new ShapeRecord(ShapeType::POINT); $record1->addPoint([ 'x' => 472131.764567, 'y' => 2143634.39608, ]); -$record2 = new ShapeRecord(1); +$record2 = new ShapeRecord(ShapeType::POINT); $record2->addPoint([ 'x' => 492131.764567, 'y' => 2143634.39608, diff --git a/examples/read.php b/examples/read.php index a1561be..38d02f1 100644 --- a/examples/read.php +++ b/examples/read.php @@ -24,6 +24,7 @@ */ use PhpMyAdmin\ShapeFile\ShapeFile; +use PhpMyAdmin\ShapeFile\ShapeType; /** * Displays content of given file. @@ -33,7 +34,7 @@ // phpcs:ignore Squiz.Functions.GlobalFunction.Found function display_file(string $filename): void { - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); $shp->loadFromFile($filename); $i = 1; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 7accd2b..bf6f6df 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,10 +1,5 @@ parameters: ignoreErrors: - - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" - count: 2 - path: src/ShapeFile.php - - message: "#^Cannot cast mixed to int\\.$#" count: 1 @@ -55,11 +50,6 @@ parameters: count: 4 path: src/ShapeRecord.php - - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" - count: 1 - path: src/ShapeRecord.php - - message: "#^Cannot access an offset on mixed\\.$#" count: 4 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 6e85e99..50bdba5 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -117,7 +117,6 @@ $pointData $pointData - $recordNumber $shapeType diff --git a/src/ShapeFile.php b/src/ShapeFile.php index 282d446..37e313d 100644 --- a/src/ShapeFile.php +++ b/src/ShapeFile.php @@ -222,11 +222,11 @@ public function addRecord(ShapeRecord $record): int $this->updateBBox('x', $record->shpData); $this->updateBBox('y', $record->shpData); - if (in_array($this->shapeType, [11, 13, 15, 18, 21, 23, 25, 28])) { + if (in_array($this->shapeType, ShapeType::MEASURED_TYPES, true)) { $this->updateBBox('m', $record->shpData); } - if (in_array($this->shapeType, [11, 13, 15, 18])) { + if (in_array($this->shapeType, ShapeType::TYPES_WITH_Z, true)) { $this->updateBBox('z', $record->shpData); } @@ -669,10 +669,12 @@ public function eofSHP(): bool /** * Returns shape name. + * + * @psalm-return non-empty-string */ public function getShapeName(): string { - return Util::nameShape($this->shapeType); + return ShapeType::name($this->shapeType); } /** diff --git a/src/ShapeRecord.php b/src/ShapeRecord.php index 50245f6..2c0e80b 100644 --- a/src/ShapeRecord.php +++ b/src/ShapeRecord.php @@ -79,19 +79,19 @@ public function loadFromFile(ShapeFile $shapeFile, $dbfFile): void } match ($this->shapeType) { - 0 => $this->loadNullRecord(), - 1 => $this->loadPointRecord(), - 21 => $this->loadPointMRecord(), - 11 => $this->loadPointZRecord(), - 3 => $this->loadPolyLineRecord(), - 23 => $this->loadPolyLineMRecord(), - 13 => $this->loadPolyLineZRecord(), - 5 => $this->loadPolygonRecord(), - 25 => $this->loadPolygonMRecord(), - 15 => $this->loadPolygonZRecord(), - 8 => $this->loadMultiPointRecord(), - 28 => $this->loadMultiPointMRecord(), - 18 => $this->loadMultiPointZRecord(), + ShapeType::NULL => $this->loadNullRecord(), + ShapeType::POINT => $this->loadPointRecord(), + ShapeType::POINT_M => $this->loadPointMRecord(), + ShapeType::POINT_Z => $this->loadPointZRecord(), + ShapeType::POLY_LINE => $this->loadPolyLineRecord(), + ShapeType::POLY_LINE_M => $this->loadPolyLineMRecord(), + ShapeType::POLY_LINE_Z => $this->loadPolyLineZRecord(), + ShapeType::POLYGON => $this->loadPolygonRecord(), + ShapeType::POLYGON_M => $this->loadPolygonMRecord(), + ShapeType::POLYGON_Z => $this->loadPolygonZRecord(), + ShapeType::MULTI_POINT => $this->loadMultiPointRecord(), + ShapeType::MULTI_POINT_M => $this->loadMultiPointMRecord(), + ShapeType::MULTI_POINT_Z => $this->loadMultiPointZRecord(), default => $this->setError(sprintf('The Shape Type "%s" is not supported.', $this->shapeType)), }; @@ -126,19 +126,19 @@ public function saveToFile($shpFile, $dbfFile, int $recordNumber): void $this->saveHeaders(); match ($this->shapeType) { - 0 => null, // Nothing to save - 1 => $this->savePointRecord(), - 21 => $this->savePointMRecord(), - 11 => $this->savePointZRecord(), - 3 => $this->savePolyLineRecord(), - 23 => $this->savePolyLineMRecord(), - 13 => $this->savePolyLineZRecord(), - 5 => $this->savePolygonRecord(), - 25 => $this->savePolygonMRecord(), - 15 => $this->savePolygonZRecord(), - 8 => $this->saveMultiPointRecord(), - 28 => $this->saveMultiPointMRecord(), - 18 => $this->saveMultiPointZRecord(), + ShapeType::NULL => null, // Nothing to save + ShapeType::POINT => $this->savePointRecord(), + ShapeType::POINT_M => $this->savePointMRecord(), + ShapeType::POINT_Z => $this->savePointZRecord(), + ShapeType::POLY_LINE => $this->savePolyLineRecord(), + ShapeType::POLY_LINE_M => $this->savePolyLineMRecord(), + ShapeType::POLY_LINE_Z => $this->savePolyLineZRecord(), + ShapeType::POLYGON => $this->savePolygonRecord(), + ShapeType::POLYGON_M => $this->savePolygonMRecord(), + ShapeType::POLYGON_Z => $this->savePolygonZRecord(), + ShapeType::MULTI_POINT => $this->saveMultiPointRecord(), + ShapeType::MULTI_POINT_M => $this->saveMultiPointMRecord(), + ShapeType::MULTI_POINT_Z => $this->saveMultiPointZRecord(), default => $this->setError(sprintf('The Shape Type "%s" is not supported.', $this->shapeType)), }; @@ -584,12 +584,12 @@ private function adjustBBox(array $point): void */ private function adjustPoint(array $point): array { - $type = $this->shapeType / 10; - if ($type >= 2) { + if (in_array($this->shapeType, ShapeType::MEASURED_TYPES, true)) { $point['m'] ??= 0.0; - } elseif ($type >= 1) { + } + + if (in_array($this->shapeType, ShapeType::TYPES_WITH_Z, true)) { $point['z'] ??= 0.0; - $point['m'] ??= 0.0; } return $point; @@ -605,30 +605,30 @@ public function addPoint(array $point, int $partIndex = 0): void { $point = $this->adjustPoint($point); switch ($this->shapeType) { - case 0: + case ShapeType::NULL: //Don't add anything return; - case 1: - case 11: - case 21: + case ShapeType::POINT: + case ShapeType::POINT_Z: + case ShapeType::POINT_M: //Substitutes the value of the current point $this->shpData = $point; break; - case 3: - case 5: - case 13: - case 15: - case 23: - case 25: + case ShapeType::POLY_LINE: + case ShapeType::POLYGON: + case ShapeType::POLY_LINE_Z: + case ShapeType::POLYGON_Z: + case ShapeType::POLY_LINE_M: + case ShapeType::POLYGON_M: //Adds a new point to the selected part $this->shpData['parts'][$partIndex]['points'][] = $point; $this->shpData['numparts'] = count($this->shpData['parts']); $this->shpData['numpoints'] = 1 + ($this->shpData['numpoints'] ?? 0); break; - case 8: - case 18: - case 28: + case ShapeType::MULTI_POINT: + case ShapeType::MULTI_POINT_Z: + case ShapeType::MULTI_POINT_M: //Adds a new point $this->shpData['points'][] = $point; $this->shpData['numpoints'] = 1 + ($this->shpData['numpoints'] ?? 0); @@ -651,30 +651,30 @@ public function addPoint(array $point, int $partIndex = 0): void public function deletePoint(int $pointIndex = 0, int $partIndex = 0): void { switch ($this->shapeType) { - case 0: + case ShapeType::NULL: //Don't delete anything break; - case 1: - case 11: - case 21: + case ShapeType::POINT: + case ShapeType::POINT_Z: + case ShapeType::POINT_M: //Sets the value of the point to zero $this->shpData['x'] = 0.0; $this->shpData['y'] = 0.0; - if (in_array($this->shapeType, [11, 21])) { + if (in_array($this->shapeType, [ShapeType::POINT_Z, ShapeType::POINT_M], true)) { $this->shpData['m'] = 0.0; } - if ($this->shapeType === 11) { + if ($this->shapeType === ShapeType::POINT_Z) { $this->shpData['z'] = 0.0; } break; - case 3: - case 5: - case 13: - case 15: - case 23: - case 25: + case ShapeType::POLY_LINE: + case ShapeType::POLYGON: + case ShapeType::POLY_LINE_Z: + case ShapeType::POLYGON_Z: + case ShapeType::POLY_LINE_M: + case ShapeType::POLYGON_M: //Deletes the point from the selected part, if exists if ( isset($this->shpData['parts'][$partIndex]) @@ -694,9 +694,9 @@ public function deletePoint(int $pointIndex = 0, int $partIndex = 0): void } break; - case 8: - case 18: - case 28: + case ShapeType::MULTI_POINT: + case ShapeType::MULTI_POINT_Z: + case ShapeType::MULTI_POINT_M: //Deletes the point, if exists if (isset($this->shpData['points'][$pointIndex])) { $count = count($this->shpData['points']) - 1; @@ -724,20 +724,20 @@ public function getContentLength(): int|null // The content length for a record is the length of the record contents section measured in 16-bit words. // one coordinate makes 4 16-bit words (64 bit double) switch ($this->shapeType) { - case 0: + case ShapeType::NULL: $result = 0; break; - case 1: + case ShapeType::POINT: $result = 10; break; - case 21: + case ShapeType::POINT_M: $result = 10 + 4; break; - case 11: + case ShapeType::POINT_Z: $result = 10 + 8; break; - case 3: - case 5: + case ShapeType::POLY_LINE: + case ShapeType::POLYGON: $count = count($this->shpData['parts']); $result = 22 + 2 * $count; for ($i = 0; $i < $count; ++$i) { @@ -745,8 +745,8 @@ public function getContentLength(): int|null } break; - case 23: - case 25: + case ShapeType::POLY_LINE_M: + case ShapeType::POLYGON_M: $count = count($this->shpData['parts']); $result = 22 + (2 * 4) + 2 * $count; for ($i = 0; $i < $count; ++$i) { @@ -754,8 +754,8 @@ public function getContentLength(): int|null } break; - case 13: - case 15: + case ShapeType::POLY_LINE_Z: + case ShapeType::POLYGON_Z: $count = count($this->shpData['parts']); $result = 22 + (4 * 4) + 2 * $count; for ($i = 0; $i < $count; ++$i) { @@ -763,13 +763,13 @@ public function getContentLength(): int|null } break; - case 8: + case ShapeType::MULTI_POINT: $result = 20 + 8 * count($this->shpData['points']); break; - case 28: + case ShapeType::MULTI_POINT_M: $result = 20 + (2 * 4) + (8 + 4) * count($this->shpData['points']); break; - case 18: + case ShapeType::MULTI_POINT_Z: $result = 20 + (4 * 4) + (8 + 8) * count($this->shpData['points']); break; default: @@ -815,9 +815,11 @@ public function setError(string $error): void /** * Returns shape name. + * + * @psalm-return non-empty-string */ public function getShapeName(): string { - return Util::nameShape($this->shapeType); + return ShapeType::name($this->shapeType); } } diff --git a/src/ShapeType.php b/src/ShapeType.php new file mode 100644 index 0000000..505d7d0 --- /dev/null +++ b/src/ShapeType.php @@ -0,0 +1,74 @@ + 'Null Shape', + self::POINT => 'Point', + self::POLY_LINE => 'PolyLine', + self::POLYGON => 'Polygon', + self::MULTI_POINT => 'MultiPoint', + self::POINT_Z => 'PointZ', + self::POLY_LINE_Z => 'PolyLineZ', + self::POLYGON_Z => 'PolygonZ', + self::MULTI_POINT_Z => 'MultiPointZ', + self::POINT_M => 'PointM', + self::POLY_LINE_M => 'PolyLineM', + self::POLYGON_M => 'PolygonM', + self::MULTI_POINT_M => 'MultiPointM', + self::MULTI_PATCH => 'MultiPatch', + ]; + + /** @psalm-return non-empty-string */ + public static function name(int $shapeType): string + { + return self::NAMES[$shapeType] ?? 'Shape ' . $shapeType; + } +} diff --git a/src/Util.php b/src/Util.php index 8a761b5..0edf299 100644 --- a/src/Util.php +++ b/src/Util.php @@ -27,7 +27,6 @@ use function current; use function pack; -use function sprintf; use function strrev; use function unpack; @@ -35,23 +34,6 @@ class Util { private static bool|null $littleEndian = null; - private const SHAPE_NAMES = [ - 0 => 'Null Shape', - 1 => 'Point', - 3 => 'PolyLine', - 5 => 'Polygon', - 8 => 'MultiPoint', - 11 => 'PointZ', - 13 => 'PolyLineZ', - 15 => 'PolygonZ', - 18 => 'MultiPointZ', - 21 => 'PointM', - 23 => 'PolyLineM', - 25 => 'PolygonM', - 28 => 'MultiPointM', - 31 => 'MultiPatch', - ]; - /** * Reads data. * @@ -86,12 +68,4 @@ public static function packDouble(float $value): string return strrev($bin); } - - /** - * Returns shape name. - */ - public static function nameShape(int $type): string - { - return self::SHAPE_NAMES[$type] ?? sprintf('Shape %d', $type); - } } diff --git a/tests/ShapeFileTest.php b/tests/ShapeFileTest.php index 8225801..64b9a5c 100644 --- a/tests/ShapeFileTest.php +++ b/tests/ShapeFileTest.php @@ -27,6 +27,7 @@ use PhpMyAdmin\ShapeFile\ShapeFile; use PhpMyAdmin\ShapeFile\ShapeRecord; +use PhpMyAdmin\ShapeFile\ShapeType; use PHPUnit\Framework\TestCase; use function count; @@ -44,7 +45,7 @@ class ShapeFileTest extends TestCase */ public function testLoad(string $filename, int $records, int|null $parts): void { - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); $shp->loadFromFile($filename); $this->assertEquals('', $shp->lastError); $this->assertEquals($records, count($shp->records)); @@ -105,7 +106,7 @@ public static function provideFiles(): array */ public function testLoadError(string $filename): void { - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); $shp->loadFromFile($filename); $this->assertNotEquals('', $shp->lastError); } @@ -115,7 +116,7 @@ public function testLoadError(string $filename): void */ public function testLoadEmptyFilename(): void { - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); $shp->loadFromFile(''); if (ShapeFile::supportsDbase()) { $this->assertEquals('It wasn\'t possible to find the DBase file ""', $shp->lastError); @@ -131,7 +132,7 @@ public function testLoadEmptyFilename(): void */ public function testGetDBFHeader(): void { - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); $this->assertNull($shp->getDBFHeader()); } @@ -161,18 +162,18 @@ public static function provideErrorFiles(): array */ private function createTestData(): void { - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); - $record0 = new ShapeRecord(1); + $record0 = new ShapeRecord(ShapeType::POINT); $record0->addPoint(['x' => 482131.764567, 'y' => 2143634.39608]); - $record1 = new ShapeRecord(11); + $record1 = new ShapeRecord(ShapeType::POINT_Z); $record1->addPoint(['x' => 472131.764567, 'y' => 2143634.39608, 'z' => 220, 'm' => 120]); - $record2 = new ShapeRecord(21); + $record2 = new ShapeRecord(ShapeType::POINT_M); $record2->addPoint(['x' => 492131.764567, 'y' => 2143634.39608, 'z' => 150, 'm' => 80]); - $record3 = new ShapeRecord(3); + $record3 = new ShapeRecord(ShapeType::POLY_LINE); $record3->addPoint(['x' => 482131.764567, 'y' => 2143634.39608], 0); $record3->addPoint(['x' => 482132.764567, 'y' => 2143635.39608], 0); $record3->addPoint(['x' => 482131.764567, 'y' => 2143635.39608], 1); @@ -226,7 +227,7 @@ public function testCreate(): void $this->createTestData(); - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); $shp->loadFromFile('./data/test_shape.*'); $this->assertEquals(4, count($shp->records)); } @@ -242,13 +243,13 @@ public function testDelete(): void $this->createTestData(); - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); $shp->loadFromFile('./data/test_shape.*'); $shp->deleteRecord(1); $shp->saveToFile(); $this->assertEquals(3, count($shp->records)); - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); $shp->loadFromFile('./data/test_shape.*'); $this->assertEquals(3, count($shp->records)); } @@ -264,10 +265,10 @@ public function testAdd(): void $this->createTestData(); - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); $shp->loadFromFile('./data/test_shape.*'); - $record0 = new ShapeRecord(1); + $record0 = new ShapeRecord(ShapeType::POINT); $record0->addPoint(['x' => 482131.764567, 'y' => 2143634.39608]); $shp->addRecord($record0); @@ -277,7 +278,7 @@ public function testAdd(): void $shp->saveToFile(); $this->assertEquals(5, count($shp->records)); - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); $shp->loadFromFile('./data/test_shape.*'); $this->assertEquals(5, count($shp->records)); } @@ -287,7 +288,7 @@ public function testAdd(): void */ public function testSaveNoDBF(): void { - $shp = new ShapeFile(1); + $shp = new ShapeFile(ShapeType::POINT); $shp->saveToFile('./data/test_nodbf.*'); $this->assertFileDoesNotExist('./data/test_nodbf.dbf'); @@ -298,9 +299,9 @@ public function testSaveNoDBF(): void */ public function testShapeName(): void { - $obj = new ShapeRecord(1); + $obj = new ShapeRecord(ShapeType::POINT); $this->assertEquals('Point', $obj->getShapeName()); - $obj = new ShapeFile(1); + $obj = new ShapeFile(ShapeType::POINT); $this->assertEquals('Point', $obj->getShapeName()); $obj = new ShapeRecord(-1); $this->assertEquals('Shape -1', $obj->getShapeName()); @@ -382,24 +383,24 @@ public static function shapesProvider(): array ]; return [ - [1, $pointsForPointType], - [3, $pointsForPolyLineType], - [5, $pointsForPolygonType], - [8, $pointsForMultiPointType], - [11, $pointsForPointType], - [13, $pointsForPolyLineType], - [15, $pointsForPolygonType], - [18, $pointsForMultiPointType], - [21, $pointsForPointType], - [23, $pointsForPolyLineType], - [25, $pointsForPolygonType], - [28, $pointsForMultiPointType], + [ShapeType::POINT, $pointsForPointType], + [ShapeType::POLY_LINE, $pointsForPolyLineType], + [ShapeType::POLYGON, $pointsForPolygonType], + [ShapeType::MULTI_POINT, $pointsForMultiPointType], + [ShapeType::POINT_Z, $pointsForPointType], + [ShapeType::POLY_LINE_Z, $pointsForPolyLineType], + [ShapeType::POLYGON_Z, $pointsForPolygonType], + [ShapeType::MULTI_POINT_Z, $pointsForMultiPointType], + [ShapeType::POINT_M, $pointsForPointType], + [ShapeType::POLY_LINE_M, $pointsForPolyLineType], + [ShapeType::POLYGON_M, $pointsForPolygonType], + [ShapeType::MULTI_POINT_M, $pointsForMultiPointType], ]; } public function testSearch(): void { - $shp = new ShapeFile(0); + $shp = new ShapeFile(ShapeType::NULL); $shp->loadFromFile('data/capitals.*'); /* Nonexisting entry or no dbase support */ $this->assertEquals(