From 8cf75adf7dc4f1d9b881b0d865383b67a09d6b7d Mon Sep 17 00:00:00 2001 From: Adam Bramley Date: Wed, 13 Jul 2022 08:19:22 +1000 Subject: [PATCH] Fixes #29: Strong type-hints (#33) * Fixes #29: Strong type-hints * Modern PHP * Add php81 executor * Add very useful @var dec * Bump squizlabs, ignore missing var decs * Bump squizlabs for lowest * Kill more var docs Co-authored-by: Lee Rowlands --- .circleci/config.yml | 9 +- .gitignore | 1 + composer.json | 13 ++- composer.lock | 170 ++++++++++++++++++++++++++-- phpcs.xml | 4 + phpstan.neon | 8 ++ src/NestedSetInterface.php | 52 ++++----- src/NestedSetSchemaInterface.php | 4 +- src/Node.php | 45 ++------ src/NodeKey.php | 21 +--- src/Storage/BaseDbalStorage.php | 19 +--- src/Storage/DbalNestedSet.php | 99 ++++++++-------- src/Storage/DbalNestedSetSchema.php | 8 +- 13 files changed, 294 insertions(+), 159 deletions(-) create mode 100644 phpstan.neon diff --git a/.circleci/config.yml b/.circleci/config.yml index 5ed9f80b..2fefd711 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,12 +1,12 @@ version: 2.1 executors: - php74: - docker: - - image: skpr/php-cli:7.4-1.x php80: docker: - image: skpr/php-cli:8.0-1.x + php81: + docker: + - image: skpr/php-cli:8.0-1.x workflows: build: @@ -14,7 +14,7 @@ workflows: - build: matrix: parameters: - php: ["php74", "php80"] + php: ["php80", "php81"] composer-opts: ["", "--prefer-lowest"] jobs: @@ -30,6 +30,7 @@ jobs: - checkout - run: composer2 update --prefer-dist --no-progress --no-suggest --no-interaction --optimize-autoloader << parameters.composer-opts >> - run: ./bin/phpcs --colors --report=full --runtime-set testVersion 8.0- + - run: php -d memory_limit=-1 ./bin/phpstan analyze --no-progress - run: mkdir -p build/phpunit - run: ./bin/phpunit --log-junit build/phpunit/results.xml - store_test_results: diff --git a/.gitignore b/.gitignore index 5f25e5cd..2bb9ceca 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /vendor/ *.sqlite .phpunit.result.cache +.idea diff --git a/composer.json b/composer.json index d6ae0a76..5f8843d1 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "minimum-stability": "dev", "prefer-stable": true, "require": { - "php": "^7.3 || ^8.0", + "php": ">=8.0", "doctrine/dbal": "^2.12.1" }, "require-dev": { @@ -21,8 +21,11 @@ "drupal/coder": "^8.3.12", "pear/console_table": "^1.3", "phpcompatibility/php-compatibility": "^9.3", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-deprecation-rules": "^1.0", "phpunit/phpunit": "^8.5 || ^9.3", - "squizlabs/php_codesniffer": "^3.5.8" + "squizlabs/php_codesniffer": "^3.7.1" }, "autoload": { "psr-4": { @@ -39,6 +42,10 @@ "preferred-install": { "*": "dist" }, - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "phpstan/extension-installer": true + } } } diff --git a/composer.lock b/composer.lock index e4718a7d..df67cb83 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bc3978591444528436441ad8ea023e5a", + "content-hash": "de2349b2f9faf7bfa252036c7c472295", "packages": [ { "name": "doctrine/cache", @@ -1066,6 +1066,160 @@ }, "time": "2020-12-19T10:15:11+00:00" }, + { + "name": "phpstan/extension-installer", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "66c7adc9dfa38b6b5838a9fb728b68a7d8348051" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/66c7adc9dfa38b6b5838a9fb728b68a7d8348051", + "reference": "66c7adc9dfa38b6b5838a9fb728b68a7d8348051", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1 || ^2.0", + "php": "^7.1 || ^8.0", + "phpstan/phpstan": ">=0.11.6" + }, + "require-dev": { + "composer/composer": "^1.8", + "phing/phing": "^2.16.3", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.1.0" + }, + "time": "2020-12-13T13:06:13+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.4.10", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "898c479c39caa727bedf4311dd294a8f4e250e72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/898c479c39caa727bedf4311dd294a8f4e250e72", + "reference": "898c479c39caa727bedf4311dd294a8f4e250e72", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "support": { + "issues": "https://github.com/phpstan/phpstan/issues", + "source": "https://github.com/phpstan/phpstan/tree/1.4.10" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpstan", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2022-03-14T10:25:45+00:00" + }, + { + "name": "phpstan/phpstan-deprecation-rules", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-deprecation-rules.git", + "reference": "e5ccafb0dd8d835dd65d8d7a1a0d2b1b75414682" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/e5ccafb0dd8d835dd65d8d7a1a0d2b1b75414682", + "reference": "e5ccafb0dd8d835dd65d8d7a1a0d2b1b75414682", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "phpstan/phpstan": "^1.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^9.5" + }, + "type": "phpstan-extension", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + }, + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", + "support": { + "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", + "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.0.0" + }, + "time": "2021-09-23T11:02:21+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.5", @@ -2506,16 +2660,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.8", + "version": "3.7.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4" + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", "shasum": "" }, "require": { @@ -2558,7 +2712,7 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2020-10-23T02:01:07+00:00" + "time": "2022-06-18T07:21:10+00:00" }, { "name": "symfony/deprecation-contracts", @@ -2891,10 +3045,10 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^7.3 || ^8.0" + "php": ">=8.0" }, "platform-dev": { "ext-pdo_sqlite": "*" }, - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.3.0" } diff --git a/phpcs.xml b/phpcs.xml index 8a472ec6..d69de226 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -9,4 +9,8 @@ + + + 0 + diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..862294e5 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,8 @@ +parameters: + level: 6 + checkMissingIterableValueType: false + paths: + - src + customRulesetUsed: true + reportUnmatchedIgnoredErrors: false + ignoreErrors: { } diff --git a/src/NestedSetInterface.php b/src/NestedSetInterface.php index 87dcdf7d..7fc20382 100644 --- a/src/NestedSetInterface.php +++ b/src/NestedSetInterface.php @@ -18,7 +18,7 @@ interface NestedSetInterface { * @return \PNX\NestedSet\Node * Returns a new node with position values set. */ - public function addNodeBelow(Node $target, NodeKey $nodeKey); + public function addNodeBelow(Node $target, NodeKey $nodeKey): Node; /** * Inserts a node before the target node. @@ -31,7 +31,7 @@ public function addNodeBelow(Node $target, NodeKey $nodeKey); * @return \PNX\NestedSet\Node * Returns a node with position values set. */ - public function addNodeBefore(Node $target, NodeKey $nodeKey); + public function addNodeBefore(Node $target, NodeKey $nodeKey): Node; /** * Inserts a node after the target node. @@ -44,7 +44,7 @@ public function addNodeBefore(Node $target, NodeKey $nodeKey); * @return \PNX\NestedSet\Node * Returns a node with position values set. */ - public function addNodeAfter(Node $target, NodeKey $nodeKey); + public function addNodeAfter(Node $target, NodeKey $nodeKey): Node; /** * Inserts a root node. @@ -55,7 +55,7 @@ public function addNodeAfter(Node $target, NodeKey $nodeKey); * @return \PNX\NestedSet\Node * A new node with position values set. */ - public function addRootNode(NodeKey $nodeKey); + public function addRootNode(NodeKey $nodeKey): Node; /** * Deletes a node and moves descendants up a level. @@ -63,7 +63,7 @@ public function addRootNode(NodeKey $nodeKey); * @param \PNX\NestedSet\Node $node * The node to delete. */ - public function deleteNode(Node $node); + public function deleteNode(Node $node): void; /** * Deletes a node and all it's descendants. @@ -71,7 +71,7 @@ public function deleteNode(Node $node); * @param \PNX\NestedSet\Node $node * The node to delete. */ - public function deleteSubTree(Node $node); + public function deleteSubTree(Node $node): void; /** * Finds all descendants of a node. @@ -83,10 +83,10 @@ public function deleteSubTree(Node $node); * @param int $start * (optional) A starting depth. Default of 1 excludes the node itself. * - * @return array + * @return \PNX\NestedSet\Node[] * The nested array of descendants. */ - public function findDescendants(NodeKey $nodeKey, $depth = 0, $start = 1); + public function findDescendants(NodeKey $nodeKey, int $depth = 0, int $start = 1): array; /** * Finds all immediate children of a node. @@ -94,10 +94,10 @@ public function findDescendants(NodeKey $nodeKey, $depth = 0, $start = 1); * @param \PNX\NestedSet\NodeKey $nodeKey * The node key to find children for. * - * @return array + * @return \PNX\NestedSet\Node[] * The children. */ - public function findChildren(NodeKey $nodeKey); + public function findChildren(NodeKey $nodeKey): array; /** * Finds all ancestors of a node. @@ -105,10 +105,10 @@ public function findChildren(NodeKey $nodeKey); * @param \PNX\NestedSet\NodeKey $nodeKey * The node to find ancestors for. * - * @return array + * @return \PNX\NestedSet\Node[] * The ancestors. */ - public function findAncestors(NodeKey $nodeKey); + public function findAncestors(NodeKey $nodeKey): array; /** * Finds the parent node. @@ -116,10 +116,10 @@ public function findAncestors(NodeKey $nodeKey); * @param \PNX\NestedSet\NodeKey $nodeKey * The node key. * - * @return \PNX\NestedSet\Node + * @return \PNX\NestedSet\Node|null * The parent node. */ - public function findParent(NodeKey $nodeKey); + public function findParent(NodeKey $nodeKey): ?Node; /** * Gets a node for the ID and Revision ID. @@ -127,10 +127,10 @@ public function findParent(NodeKey $nodeKey); * @param NodeKey $nodeKey * The node key. * - * @return \PNX\NestedSet\Node + * @return \PNX\NestedSet\Node|null * The node. */ - public function getNode(NodeKey $nodeKey); + public function getNode(NodeKey $nodeKey): ?Node; /** * Moves a subtree to be a new root of the tree. @@ -138,7 +138,7 @@ public function getNode(NodeKey $nodeKey); * @param \PNX\NestedSet\Node $node * The node to become the new root node. */ - public function moveSubTreeToRoot(Node $node); + public function moveSubTreeToRoot(Node $node): void; /** * Moves a node and its sub-tree below the target node. @@ -148,7 +148,7 @@ public function moveSubTreeToRoot(Node $node); * @param \PNX\NestedSet\Node $node * The node to move. */ - public function moveSubTreeBelow(Node $target, Node $node); + public function moveSubTreeBelow(Node $target, Node $node): void; /** * Moves a node and its sub-tree before the target node. @@ -158,7 +158,7 @@ public function moveSubTreeBelow(Node $target, Node $node); * @param \PNX\NestedSet\Node $node * The node to move. */ - public function moveSubTreeBefore(Node $target, Node $node); + public function moveSubTreeBefore(Node $target, Node $node): void; /** * Moves a node and its sub-tree after the target node. @@ -168,7 +168,7 @@ public function moveSubTreeBefore(Node $target, Node $node); * @param \PNX\NestedSet\Node $node * The node to move. */ - public function moveSubTreeAfter(Node $target, Node $node); + public function moveSubTreeAfter(Node $target, Node $node): void; /** * Swaps the parent of a sub-tree to a new parent. @@ -178,7 +178,7 @@ public function moveSubTreeAfter(Node $target, Node $node); * @param \PNX\NestedSet\Node $newParent * The new parent. */ - public function adoptChildren(Node $oldParent, Node $newParent); + public function adoptChildren(Node $oldParent, Node $newParent): void; /** * Gets a node at a specified left position. @@ -189,15 +189,15 @@ public function adoptChildren(Node $oldParent, Node $newParent); * @return Node * The node. */ - public function getNodeAtPosition($left); + public function getNodeAtPosition(int $left): ?Node; /** * Fetches the entire tree. * - * @return array + * @return \PNX\NestedSet\Node[] * The tree. */ - public function getTree(); + public function getTree(): array; /** * Finds the root node for this node. @@ -205,9 +205,9 @@ public function getTree(); * @param \PNX\NestedSet\NodeKey $nodeKey * The node key. * - * @return \PNX\NestedSet\Node + * @return \PNX\NestedSet\Node|null * The root node. */ - public function findRoot(NodeKey $nodeKey); + public function findRoot(NodeKey $nodeKey): ?Node; } diff --git a/src/NestedSetSchemaInterface.php b/src/NestedSetSchemaInterface.php index b9d7431d..fdd6e7b7 100644 --- a/src/NestedSetSchemaInterface.php +++ b/src/NestedSetSchemaInterface.php @@ -10,11 +10,11 @@ interface NestedSetSchemaInterface { /** * Creates the nested set table. */ - public function create(); + public function create(): void; /** * Drops the nested set table. */ - public function drop(); + public function drop(): void; } diff --git a/src/Node.php b/src/Node.php index 89cbdf33..dc03d8c0 100644 --- a/src/Node.php +++ b/src/Node.php @@ -7,33 +7,10 @@ */ class Node { - /** - * The node key. - * - * @var NodeKey - */ - protected $nodeKey; - - /** - * The left value. - * - * @var int - */ - protected $left; - - /** - * The right value. - * - * @var int - */ - protected $right; - - /** - * The depth. - * - * @var int - */ - protected $depth; + protected NodeKey $nodeKey; + protected int $left; + protected int $right; + protected int $depth; /** * Node constructor. @@ -47,7 +24,7 @@ class Node { * @param int $depth * The depth. */ - public function __construct(NodeKey $nodeKey, $left, $right, $depth) { + public function __construct(NodeKey $nodeKey, int $left, int $right, int $depth) { if ($nodeKey == NULL) { throw new \InvalidArgumentException("Node key cannot be NULL"); } @@ -72,7 +49,7 @@ public function __construct(NodeKey $nodeKey, $left, $right, $depth) { * @return int|string * The ID. */ - public function getId() { + public function getId(): int|string { return $this->nodeKey->getId(); } @@ -82,7 +59,7 @@ public function getId() { * @return int|string * The revision ID. */ - public function getRevisionId() { + public function getRevisionId(): int|string { return $this->nodeKey->getRevisionId(); } @@ -92,7 +69,7 @@ public function getRevisionId() { * @return \PNX\NestedSet\NodeKey * The node key. */ - public function getNodeKey() { + public function getNodeKey(): NodeKey { return $this->nodeKey; } @@ -102,7 +79,7 @@ public function getNodeKey() { * @return int * The left value. */ - public function getLeft() { + public function getLeft(): int { return $this->left; } @@ -112,7 +89,7 @@ public function getLeft() { * @return int * The right value. */ - public function getRight() { + public function getRight(): int { return $this->right; } @@ -122,7 +99,7 @@ public function getRight() { * @return int * The depth. */ - public function getDepth() { + public function getDepth(): int { return $this->depth; } diff --git a/src/NodeKey.php b/src/NodeKey.php index 17d5cd48..67131552 100644 --- a/src/NodeKey.php +++ b/src/NodeKey.php @@ -7,19 +7,8 @@ */ class NodeKey { - /** - * The node ID. - * - * @var string|int - */ - protected $id; - - /** - * The revision ID. - * - * @var string|int - */ - protected $revisionId; + protected string|int $id; + protected string|int $revisionId; /** * NodeKey constructor. @@ -29,7 +18,7 @@ class NodeKey { * @param int|string $revisionId * The node revision id. */ - public function __construct($id, $revisionId) { + public function __construct(string|int $id, string|int $revisionId) { $this->id = $id; $this->revisionId = $revisionId; } @@ -40,7 +29,7 @@ public function __construct($id, $revisionId) { * @return int|string * The node id. */ - public function getId() { + public function getId(): string|int { return $this->id; } @@ -50,7 +39,7 @@ public function getId() { * @return int|string * The node revision id. */ - public function getRevisionId() { + public function getRevisionId(): string|int { return $this->revisionId; } diff --git a/src/Storage/BaseDbalStorage.php b/src/Storage/BaseDbalStorage.php index f1d131e3..32358e36 100644 --- a/src/Storage/BaseDbalStorage.php +++ b/src/Storage/BaseDbalStorage.php @@ -14,19 +14,8 @@ abstract class BaseDbalStorage { */ const VALID_TABLE_REGEX = '/^[a-zA-Z]\w{1,64}$/'; - /** - * The database connection. - * - * @var \Doctrine\DBAL\Connection - */ - protected $connection; - - /** - * The table name to use for storing the nested set. - * - * @var string - */ - protected $tableName; + protected Connection $connection; + protected string $tableName; /** * DbalTree constructor. @@ -36,7 +25,7 @@ abstract class BaseDbalStorage { * @param string $tableName * (optional) The table name to use. */ - public function __construct(Connection $connection, $tableName = 'tree') { + public function __construct(Connection $connection, string $tableName = 'tree') { $this->connection = $connection; if (!$this->validTableName($tableName)) { throw new \InvalidArgumentException("Table name must match the regex " . self::VALID_TABLE_REGEX); @@ -58,7 +47,7 @@ public function __construct(Connection $connection, $tableName = 'tree') { * @return bool * TRUE if the table name is valid. */ - protected function validTableName($tableName) { + protected function validTableName(string $tableName): bool { return (bool) preg_match(self::VALID_TABLE_REGEX, $tableName); } diff --git a/src/Storage/DbalNestedSet.php b/src/Storage/DbalNestedSet.php index 72780766..54eec11c 100644 --- a/src/Storage/DbalNestedSet.php +++ b/src/Storage/DbalNestedSet.php @@ -2,6 +2,7 @@ namespace PNX\NestedSet\Storage; +use Doctrine\DBAL\Driver\Result; use PNX\NestedSet\NestedSetInterface; use PNX\NestedSet\Node; use PNX\NestedSet\NodeKey; @@ -14,7 +15,7 @@ class DbalNestedSet extends BaseDbalStorage implements NestedSetInterface { /** * {@inheritdoc} */ - public function addRootNode(NodeKey $nodeKey) { + public function addRootNode(NodeKey $nodeKey): Node { $maxRight = $this->findMaxRightPosition(); return $this->doInsertNode($nodeKey, $maxRight + 1, $maxRight + 2, 0); } @@ -22,7 +23,7 @@ public function addRootNode(NodeKey $nodeKey) { /** * {@inheritdoc} */ - public function addNodeBelow(Node $target, NodeKey $nodeKey) { + public function addNodeBelow(Node $target, NodeKey $nodeKey): Node { $target = $this->ensureNodeIsFresh($target); $newLeftPosition = $target->getRight(); $depth = $target->getDepth() + 1; @@ -32,7 +33,7 @@ public function addNodeBelow(Node $target, NodeKey $nodeKey) { /** * {@inheritdoc} */ - public function addNodeBefore(Node $target, NodeKey $nodeKey) { + public function addNodeBefore(Node $target, NodeKey $nodeKey): Node { $target = $this->ensureNodeIsFresh($target); $newLeftPosition = $target->getLeft(); $depth = $target->getDepth(); @@ -42,7 +43,7 @@ public function addNodeBefore(Node $target, NodeKey $nodeKey) { /** * {@inheritdoc} */ - public function addNodeAfter(Node $target, NodeKey $nodeKey) { + public function addNodeAfter(Node $target, NodeKey $nodeKey): Node { $target = $this->ensureNodeIsFresh($target); $newLeftPosition = $target->getRight() + 1; $depth = $target->getDepth(); @@ -65,17 +66,17 @@ public function addNodeAfter(Node $target, NodeKey $nodeKey) { * @throws \Exception * If a transaction error occurs. */ - protected function insertNodeAtPostion($newLeftPosition, $depth, NodeKey $nodeKey) { + protected function insertNodeAtPostion(int $newLeftPosition, int $depth, NodeKey $nodeKey): Node { try { $this->connection->setAutoCommit(FALSE); $this->connection->beginTransaction(); // Make space for inserting node. - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET right_pos = right_pos + 2 WHERE right_pos >= ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET right_pos = right_pos + 2 WHERE right_pos >= ?', [$newLeftPosition] ); - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET left_pos = left_pos + 2 WHERE left_pos >= ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET left_pos = left_pos + 2 WHERE left_pos >= ?', [$newLeftPosition] ); @@ -109,7 +110,7 @@ protected function insertNodeAtPostion($newLeftPosition, $depth, NodeKey $nodeKe * @return \PNX\NestedSet\Node * The new node. */ - protected function doInsertNode(NodeKey $nodeKey, $left, $right, $depth) { + protected function doInsertNode(NodeKey $nodeKey, int $left, int $right, int $depth): Node { // Create a new node object to be returned. $newNode = new Node($nodeKey, $left, $right, $depth); @@ -128,7 +129,7 @@ protected function doInsertNode(NodeKey $nodeKey, $left, $right, $depth) { /** * {@inheritdoc} */ - public function findDescendants(NodeKey $nodeKey, $depth = 0, $start = 1) { + public function findDescendants(NodeKey $nodeKey, int $depth = 0, int $start = 1): array { $descendants = []; $query = $this->connection->createQueryBuilder(); $query->select('child.id', 'child.revision_id', 'child.left_pos', 'child.right_pos', 'child.depth') @@ -150,7 +151,8 @@ public function findDescendants(NodeKey $nodeKey, $depth = 0, $start = 1) { ->setParameter(':depth', $start + $depth - 1); } $stmt = $query->execute(); - while ($row = $stmt->fetch()) { + assert($stmt instanceof Result); + while ($row = $stmt->fetchAssociative()) { $descendants[] = new Node(new NodeKey($row['id'], $row['revision_id']), $row['left_pos'], $row['right_pos'], $row['depth']); } return $descendants; @@ -159,7 +161,7 @@ public function findDescendants(NodeKey $nodeKey, $depth = 0, $start = 1) { /** * {@inheritdoc} */ - public function findChildren(NodeKey $nodeKey) { + public function findChildren(NodeKey $nodeKey): array { // Only find descendants one level deep. return $this->findDescendants($nodeKey, 1); } @@ -167,24 +169,26 @@ public function findChildren(NodeKey $nodeKey) { /** * {@inheritdoc} */ - public function getNode(NodeKey $nodeKey) { - $result = $this->connection->fetchAssoc("SELECT id, revision_id, left_pos, right_pos, depth FROM " . $this->tableName . " WHERE id = ? AND revision_id = ?", + public function getNode(NodeKey $nodeKey): ?Node { + $result = $this->connection->fetchAssociative("SELECT id, revision_id, left_pos, right_pos, depth FROM " . $this->tableName . " WHERE id = ? AND revision_id = ?", [$nodeKey->getId(), $nodeKey->getRevisionId()] ); if ($result) { return new Node($nodeKey, $result['left_pos'], $result['right_pos'], $result['depth']); } + return NULL; } /** * {@inheritdoc} */ - public function findAncestors(NodeKey $nodeKey) { + public function findAncestors(NodeKey $nodeKey): array { $ancestors = []; $stmt = $this->connection->executeQuery('SELECT parent.id, parent.revision_id, parent.left_pos, parent.right_pos, parent.depth FROM ' . $this->tableName . ' AS child, ' . $this->tableName . ' AS parent WHERE child.left_pos BETWEEN parent.left_pos AND parent.right_pos AND child.id = ? AND child.revision_id = ? ORDER BY parent.left_pos', [$nodeKey->getId(), $nodeKey->getRevisionId()] ); - while ($row = $stmt->fetch()) { + assert($stmt instanceof Result); + while ($row = $stmt->fetchAssociative()) { $ancestors[] = new Node(new NodeKey($row['id'], $row['revision_id']), $row['left_pos'], $row['right_pos'], $row['depth']); } return $ancestors; @@ -193,7 +197,7 @@ public function findAncestors(NodeKey $nodeKey) { /** * {@inheritdoc} */ - public function findRoot(NodeKey $nodeKey) { + public function findRoot(NodeKey $nodeKey): ?Node { $ancestors = $this->findAncestors($nodeKey); if (!empty($ancestors)) { return array_shift($ancestors); @@ -204,7 +208,7 @@ public function findRoot(NodeKey $nodeKey) { /** * {@inheritdoc} */ - public function findParent(NodeKey $nodeKey) { + public function findParent(NodeKey $nodeKey): ?Node { $ancestors = $this->findAncestors($nodeKey); if (count($ancestors) > 1) { // Parent is 2nd-last element. @@ -216,10 +220,11 @@ public function findParent(NodeKey $nodeKey) { /** * {@inheritdoc} */ - public function getTree() { + public function getTree(): array { $tree = []; $stmt = $this->connection->executeQuery('SELECT id, revision_id, left_pos, right_pos, depth FROM ' . $this->tableName . ' ORDER BY left_pos'); - while ($row = $stmt->fetch()) { + assert($stmt instanceof Result); + while ($row = $stmt->fetchAssociative()) { $tree[] = new Node(new NodeKey($row['id'], $row['revision_id']), $row['left_pos'], $row['right_pos'], $row['depth']); } return $tree; @@ -228,34 +233,33 @@ public function getTree() { /** * {@inheritdoc} */ - public function deleteNode(Node $node) { + public function deleteNode(Node $node): void { $node = $this->ensureNodeIsFresh($node); if ($node->getLeft() < 1 || $node->getRight() < 1) { throw new \InvalidArgumentException("Left and right values must be > 0"); } $left = $node->getLeft(); $right = $node->getRight(); - $width = $right - $left + 1; try { $this->connection->setAutoCommit(FALSE); $this->connection->beginTransaction(); // Delete the node. - $this->connection->executeUpdate('DELETE FROM ' . $this->tableName . ' WHERE left_pos = ?', + $this->connection->executeStatement('DELETE FROM ' . $this->tableName . ' WHERE left_pos = ?', [$left] ); // Move children up a level. - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET right_pos = right_pos - 1, left_pos = left_pos - 1, depth = depth -1 WHERE left_pos BETWEEN ? AND ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET right_pos = right_pos - 1, left_pos = left_pos - 1, depth = depth -1 WHERE left_pos BETWEEN ? AND ?', [$left, $right] ); // Move everything back two places. - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET right_pos = right_pos - 2 WHERE right_pos > ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET right_pos = right_pos - 2 WHERE right_pos > ?', [$right] ); - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET left_pos = left_pos - 2 WHERE left_pos > ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET left_pos = left_pos - 2 WHERE left_pos > ?', [$right] ); @@ -274,7 +278,7 @@ public function deleteNode(Node $node) { /** * {@inheritdoc} */ - public function deleteSubTree(Node $node) { + public function deleteSubTree(Node $node): void { $node = $this->ensureNodeIsFresh($node); $left = $node->getLeft(); $right = $node->getRight(); @@ -285,15 +289,15 @@ public function deleteSubTree(Node $node) { $this->connection->beginTransaction(); // Delete the node. - $this->connection->executeUpdate('DELETE FROM ' . $this->tableName . ' WHERE left_pos BETWEEN ? AND ?', + $this->connection->executeStatement('DELETE FROM ' . $this->tableName . ' WHERE left_pos BETWEEN ? AND ?', [$left, $right] ); // Move everything back two places. - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET right_pos = right_pos - ? WHERE right_pos > ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET right_pos = right_pos - ? WHERE right_pos > ?', [$width, $right] ); - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET left_pos = left_pos - ? WHERE left_pos > ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET left_pos = left_pos - ? WHERE left_pos > ?', [$width, $right] ); @@ -311,7 +315,7 @@ public function deleteSubTree(Node $node) { /** * {@inheritdoc} */ - public function moveSubTreeToRoot(Node $node) { + public function moveSubTreeToRoot(Node $node): void { $root = $this->findRoot($node->getNodeKey()); $this->moveSubTreeBefore($root, $node); } @@ -319,7 +323,7 @@ public function moveSubTreeToRoot(Node $node) { /** * {@inheritdoc} */ - public function moveSubTreeBelow(Node $target, Node $node) { + public function moveSubTreeBelow(Node $target, Node $node): void { $target = $this->ensureNodeIsFresh($target); $newLeftPosition = $target->getLeft() + 1; $this->moveSubTreeToPosition($newLeftPosition, $node, $target->getDepth() + 1); @@ -328,7 +332,7 @@ public function moveSubTreeBelow(Node $target, Node $node) { /** * {@inheritdoc} */ - public function moveSubTreeBefore(Node $target, Node $node) { + public function moveSubTreeBefore(Node $target, Node $node): void { $target = $this->ensureNodeIsFresh($target); $newLeftPosition = $target->getLeft(); $this->moveSubTreeToPosition($newLeftPosition, $node, $target->getDepth()); @@ -337,7 +341,7 @@ public function moveSubTreeBefore(Node $target, Node $node) { /** * {@inheritdoc} */ - public function moveSubTreeAfter(Node $target, Node $node) { + public function moveSubTreeAfter(Node $target, Node $node): void { $target = $this->ensureNodeIsFresh($target); $newLeftPosition = $target->getRight() + 1; $this->moveSubTreeToPosition($newLeftPosition, $node, $target->getDepth()); @@ -346,7 +350,7 @@ public function moveSubTreeAfter(Node $target, Node $node) { /** * {@inheritdoc} */ - public function adoptChildren(Node $oldParent, Node $newParent) { + public function adoptChildren(Node $oldParent, Node $newParent): void { $children = $this->findChildren($oldParent->getNodeKey()); $newParent = $this->ensureNodeIsFresh($newParent); $newLeftPosition = $newParent->getRight(); @@ -366,7 +370,7 @@ public function adoptChildren(Node $oldParent, Node $newParent) { * @throws \Exception * If a transaction error occurs. */ - protected function moveSubTreeToPosition($newLeftPosition, Node $node, $newDepth) { + protected function moveSubTreeToPosition(int $newLeftPosition, Node $node, int $newDepth): void { $this->moveMultipleSubTreesToPosition($newLeftPosition, [$node], $newDepth); } @@ -383,7 +387,7 @@ protected function moveSubTreeToPosition($newLeftPosition, Node $node, $newDepth * @throws \Exception * If a transaction error occurs. */ - protected function moveMultipleSubTreesToPosition($newLeftPosition, array $nodes, $newDepth) { + protected function moveMultipleSubTreesToPosition(int $newLeftPosition, array $nodes, int $newDepth): void { try { $firstNode = $this->ensureNodeIsFresh(reset($nodes)); @@ -406,25 +410,25 @@ protected function moveMultipleSubTreesToPosition($newLeftPosition, array $nodes } // Create new space for subtree. - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET left_pos = left_pos + ? WHERE left_pos >= ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET left_pos = left_pos + ? WHERE left_pos >= ?', [$width, $newLeftPosition] ); - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET right_pos = right_pos + ? WHERE right_pos >= ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET right_pos = right_pos + ? WHERE right_pos >= ?', [$width, $newLeftPosition] ); // Move subtree into new space. - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET left_pos = left_pos + ?, right_pos = right_pos + ?, depth = depth + ? WHERE left_pos >= ? AND right_pos < ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET left_pos = left_pos + ?, right_pos = right_pos + ?, depth = depth + ? WHERE left_pos >= ? AND right_pos < ?', [$distance, $distance, $depthDiff, $tempPos, $tempPos + $width] ); // Remove old space vacated by subtree. - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET left_pos = left_pos - ? WHERE left_pos > ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET left_pos = left_pos - ? WHERE left_pos > ?', [$width, $lastNode->getRight()] ); - $this->connection->executeUpdate('UPDATE ' . $this->tableName . ' SET right_pos = right_pos - ? WHERE right_pos > ?', + $this->connection->executeStatement('UPDATE ' . $this->tableName . ' SET right_pos = right_pos - ? WHERE right_pos > ?', [$width, $lastNode->getRight()] ); $this->connection->commit(); @@ -441,13 +445,14 @@ protected function moveMultipleSubTreesToPosition($newLeftPosition, array $nodes /** * {@inheritdoc} */ - public function getNodeAtPosition($left) { - $result = $this->connection->fetchAssoc("SELECT id, revision_id, left_pos, right_pos, depth FROM " . $this->tableName . " WHERE left_pos = ?", + public function getNodeAtPosition(int $left): ?Node { + $result = $this->connection->fetchAssociative("SELECT id, revision_id, left_pos, right_pos, depth FROM " . $this->tableName . " WHERE left_pos = ?", [$left] ); if ($result) { return new Node(new NodeKey($result['id'], $result['revision_id']), $result['left_pos'], $result['right_pos'], $result['depth']); } + return NULL; } /** @@ -456,9 +461,9 @@ public function getNodeAtPosition($left) { * @return int * The max right position. */ - protected function findMaxRightPosition() { - $maxRight = $this->connection->fetchColumn('SELECT MAX(right_pos) FROM ' . $this->tableName); - if ($maxRight === FALSE) { + protected function findMaxRightPosition(): int { + $maxRight = $this->connection->fetchOne('SELECT MAX(right_pos) FROM ' . $this->tableName); + if ($maxRight === NULL) { $maxRight = 0; } return $maxRight; @@ -473,7 +478,7 @@ protected function findMaxRightPosition() { * @return \PNX\NestedSet\Node * Fresh node. */ - protected function ensureNodeIsFresh(Node $node) { + protected function ensureNodeIsFresh(Node $node): ?Node { return $this->getNode($node->getNodeKey()); } diff --git a/src/Storage/DbalNestedSetSchema.php b/src/Storage/DbalNestedSetSchema.php index a30f07e5..156e5dc3 100644 --- a/src/Storage/DbalNestedSetSchema.php +++ b/src/Storage/DbalNestedSetSchema.php @@ -13,7 +13,7 @@ class DbalNestedSetSchema extends BaseDbalStorage implements NestedSetSchemaInte /** * {@inheritdoc} */ - public function create() { + public function create(): void { $schema = new Schema(); $tree = $schema->createTable($this->tableName); $tree->addColumn("id", "integer", ["unsigned" => TRUE]); @@ -29,18 +29,18 @@ public function create() { $tree->addIndex(['right_pos']); foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) { - $this->connection->exec($sql); + $this->connection->executeStatement($sql); } } /** * {@inheritdoc} */ - public function drop() { + public function drop(): void { $schema = new Schema(); $schema->dropTable($this->tableName); foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) { - $this->connection->exec($sql); + $this->connection->executeStatement($sql); } }