diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 31130e52..cc83b173 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -40,3 +40,16 @@ jobs: uses: docker://oskarstark/phpstan-ga with: args: analyze --no-progress -c phpstan.tests.neon.dist + + php-cs-fixer: + name: PHP-CS-Fixer + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: PHP-CS-Fixer + uses: docker://oskarstark/php-cs-fixer-ga + with: + args: --dry-run --diff diff --git a/.github/workflows/test-application.yaml b/.github/workflows/test-application.yaml index 9e15c895..cc3ec50b 100644 --- a/.github/workflows/test-application.yaml +++ b/.github/workflows/test-application.yaml @@ -17,15 +17,12 @@ jobs: fail-fast: false matrix: include: - - php-version: '7.2' - dependencies: 'lowest' - - php-version: '7.3' - - php-version: '7.4' - - php-version: '8.0' - php-version: '8.0' - dev-dependencies: true + dependencies: 'lowest' - php-version: '8.1' - php-version: '8.2' + - php-version: '8.3' + - php-version: '8.3' steps: - name: Checkout project diff --git a/.gitignore b/.gitignore index bb6966fc..35e5af6d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ cli-config.php - +.php-cs-fixer.cache vendor/ composer.phar -composer.lock \ No newline at end of file +composer.lock diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 00000000..92bc7484 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,18 @@ +in(__DIR__.'/src') + ->in(__DIR__.'/tests') + ->name('*.php') +; + +$config = new PhpCsFixer\Config(); + +return $config + ->setRiskyAllowed(true) + ->setRules([ + '@Symfony' => true, + 'single_line_throw' => false, + ]) + ->setFinder($finder) +; diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index 5e45ebb5..00000000 --- a/.styleci.yml +++ /dev/null @@ -1,6 +0,0 @@ -preset: recommended - -enabled: - - no_useless_else -disabled: - - align_double_arrow diff --git a/CHANGELOG.md b/CHANGELOG.md index b85a5882..c560bbc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,30 @@ Changelog ========= +2.x +--- + +2.0.2 +----- + +* Return type for `PHPCR\Util\QOM\QueryBuilder::getQuery` is not nullable. + +2.0.1 +----- + +* The SQL generator now escapes single quotes `'`. This avoids SQL injection risks. If you escaped + strings manually (by duplicating the `'`) you will need to stop doing that as otherwise the query + will be run with duplicated single quotes. + +2.0.0 +----- + +* Support Symfony 7 +* Drop support for Symfony 2 +* Remove deprecated code, clean up workarounds for Symfony 2. +* Drop support for PHP 7, test with PHP 8.3 +* Adjusted commands to have the return type declarations. + 1.x --- diff --git a/composer.json b/composer.json index 655bd180..843324f6 100644 --- a/composer.json +++ b/composer.json @@ -27,14 +27,15 @@ } ], "require": { - "php": "^7.2 || ^8.0", + "php": "^8.0", "phpcr/phpcr": "~2.1.0", - "symfony/console": "^2.3 || ^3.0 || ^4.0 || ^5.0 || ^6.0" + "symfony/console": "^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0" }, "require-dev": { "ramsey/uuid": "^3.5", "phpunit/phpunit": "^7.5 || ^8.0 || ^9.0", - "phpstan/phpstan": "^1.9" + "phpstan/phpstan": "^1.9", + "friendsofphp/php-cs-fixer": "^3.40" }, "suggest": { "ramsey/uuid": "A library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID)." diff --git a/phpstan.neon.dist b/phpstan.neon.dist index bc5b3efe..6fc94366 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,9 +1,16 @@ parameters: - level: 2 + level: 5 paths: - - src + - src/ + ignoreErrors: + # phpstan does not understand that the empty arrays are only the default - - message: "#Symfony\\\\Component\\\\Console\\\\Helper\\\\DialogHelper#" - count: 3 - path: src/PHPCR/Util/Console/Command/BaseCommand.php + message: "#^Empty array passed to foreach\\.$#" + count: 5 + path: src/PHPCR/Util/Console/Helper/PhpcrHelper.php + # only formulated in phpdoc that the return value must be countable + - + message: "#expects array|Countable, Iterator given\\.$#" + count: 1 + path: src/PHPCR/Util/Console/Command/NodesUpdateCommand.php diff --git a/phpstan.tests.neon.dist b/phpstan.tests.neon.dist index 0efe94d4..d7889e1f 100644 --- a/phpstan.tests.neon.dist +++ b/phpstan.tests.neon.dist @@ -1,4 +1,20 @@ parameters: - level: 1 + level: 7 paths: - - tests + - tests/ + + excludePaths: + analyse: + - tests/*/Fixtures/* + + ignoreErrors: + # too pedantic for tests + - + message: "#^Parameter \\#1 \\.\\.\\.\\$arrays of function array_merge expects array, array\\\\|false given\\.$#" + count: 1 + path: tests/PHPCR/Tests/Util/CND/Reader/FileReaderTest.php + + - + message: "#^Parameter \\#3 \\.\\.\\.\\$arrays of function array_merge expects array, array\\\\|false given\\.$#" + count: 1 + path: tests/PHPCR/Tests/Util/CND/Reader/FileReaderTest.php diff --git a/src/PHPCR/Util/CND/Exception/ParserException.php b/src/PHPCR/Util/CND/Exception/ParserException.php index a08d67e4..3cb73bdc 100644 --- a/src/PHPCR/Util/CND/Exception/ParserException.php +++ b/src/PHPCR/Util/CND/Exception/ParserException.php @@ -1,5 +1,7 @@ peek(); $msg = sprintf("PARSER ERROR: %s. Current token is [%s, '%s'] at line %s, column %s", $msg, GenericToken::getTypeName($token->getType()), $token->getData(), $token->getLine(), $token->getRow()); // construct a lookup of the next tokens $lookup = ''; - for ($i = 1; $i <= 5; $i++) { + for ($i = 1; $i <= 5; ++$i) { if ($queue->isEof()) { break; } diff --git a/src/PHPCR/Util/CND/Exception/ScannerException.php b/src/PHPCR/Util/CND/Exception/ScannerException.php index 8f201514..5b1c2449 100644 --- a/src/PHPCR/Util/CND/Exception/ScannerException.php +++ b/src/PHPCR/Util/CND/Exception/ScannerException.php @@ -1,5 +1,7 @@ tokenQueue->isEof()) { return false; @@ -53,7 +45,7 @@ protected function checkToken($type, $data = null, $ignoreCase = false) if ($data && $token->getData() !== $data) { if ($ignoreCase && is_string($data) && is_string($token->getData())) { - return strcasecmp($data, $token->getData()); + return 0 !== strcasecmp($data, $token->getData()); } return false; @@ -65,12 +57,9 @@ protected function checkToken($type, $data = null, $ignoreCase = false) /** * Check if the token data is one of the elements of the data array. * - * @param int $type - * @param array $data - * - * @return bool + * @param string[] $data */ - protected function checkTokenIn($type, array $data, $ignoreCase = false) + protected function checkTokenIn(int $type, array $data, bool $ignoreCase = false): bool { foreach ($data as $d) { if ($this->checkToken($type, $d, $ignoreCase)) { @@ -86,20 +75,18 @@ protected function checkTokenIn($type, array $data, $ignoreCase = false) * otherwise throw an exception. * * @param int $type The expected token type - * @param null|string $data The expected token data or null + * @param string|null $data The expected token data or null * * @throws ParserException - * - * @return Token */ - protected function expectToken($type, $data = null) + protected function expectToken(int $type, ?string $data = null): Token { $token = $this->tokenQueue->peek(); if (!$this->checkToken($type, $data)) { throw new ParserException($this->tokenQueue, sprintf("Expected token [%s, '%s']", Token::getTypeName($type), $data)); } - + \assert($token instanceof GenericToken); $this->tokenQueue->next(); return $token; @@ -110,11 +97,9 @@ protected function expectToken($type, $data = null) * return false. * * @param int $type The expected token type - * @param null|string $data The expected token data or null - * - * @return bool|Token + * @param string|null $data The expected token data or null */ - protected function checkAndExpectToken($type, $data = null) + protected function checkAndExpectToken(int $type, ?string $data = null): false|Token { if ($this->checkToken($type, $data)) { $token = $this->tokenQueue->peek(); diff --git a/src/PHPCR/Util/CND/Parser/CndParser.php b/src/PHPCR/Util/CND/Parser/CndParser.php index dab5dc9e..33dd38d5 100644 --- a/src/PHPCR/Util/CND/Parser/CndParser.php +++ b/src/PHPCR/Util/CND/Parser/CndParser.php @@ -1,8 +1,11 @@ * @author David Buchmann */ -class CndParser extends AbstractParser +final class CndParser extends AbstractParser { // node type attributes - private $ORDERABLE = ['o', 'ord', 'orderable']; //, 'variant' => true); - private $MIXIN = ['m', 'mix', 'mixin']; //, 'variant' => true); - private $ABSTRACT = ['a', 'abs', 'abstract']; //, 'variant' => true); - private $NOQUERY = ['noquery', 'nq']; //, 'variant' => false); - private $QUERY = ['query', 'q']; //, 'variant' => false); - private $PRIMARYITEM = ['primaryitem', '!']; //, 'variant' => false); + private array $ORDERABLE = ['o', 'ord', 'orderable']; // , 'variant' => true); + private array $MIXIN = ['m', 'mix', 'mixin']; // , 'variant' => true); + private array $ABSTRACT = ['a', 'abs', 'abstract']; // , 'variant' => true); + private array $NOQUERY = ['noquery', 'nq']; // , 'variant' => false); + private array $QUERY = ['query', 'q']; // , 'variant' => false); + private array $PRIMARYITEM = ['primaryitem', '!']; // , 'variant' => false); // common for properties and child definitions - private $PRIMARY = ['!', 'pri', 'primary']; //, 'variant' => true), - private $AUTOCREATED = ['a', 'aut', 'autocreated']; //, 'variant' => true), - private $MANDATORY = ['m', 'man', 'mandatory']; //, 'variant' => true), - private $PROTECTED = ['p', 'pro', 'protected']; //, 'variant' => true), - private $OPV = ['COPY', 'VERSION', 'INITIALIZE', 'COMPUTE', 'IGNORE', 'ABORT']; + private array $PRIMARY = ['!', 'pri', 'primary']; // , 'variant' => true), + private array $AUTOCREATED = ['a', 'aut', 'autocreated']; // , 'variant' => true), + private array $MANDATORY = ['m', 'man', 'mandatory']; // , 'variant' => true), + private array $PROTECTED = ['p', 'pro', 'protected']; // , 'variant' => true), + private array $OPV = ['COPY', 'VERSION', 'INITIALIZE', 'COMPUTE', 'IGNORE', 'ABORT']; // property type attributes - private $MULTIPLE = ['*', 'mul', 'multiple']; //, 'variant' => true), - private $QUERYOPS = ['qop', 'queryops']; //, 'variant' => true), // Needs special handling ! - private $NOFULLTEXT = ['nof', 'nofulltext']; //, 'variant' => true), - private $NOQUERYORDER = ['nqord', 'noqueryorder']; //, 'variant' => true), + private array $MULTIPLE = ['*', 'mul', 'multiple']; // , 'variant' => true), + private array $QUERYOPS = ['qop', 'queryops']; // , 'variant' => true), // Needs special handling ! + private array $NOFULLTEXT = ['nof', 'nofulltext']; // , 'variant' => true), + private array $NOQUERYORDER = ['nqord', 'noqueryorder']; // , 'variant' => true), // child node attributes // multiple is actually a jackrabbit specific synonym for sns // http://www.mail-archive.com/users@jackrabbit.apache.org/msg19268.html - private $SNS = ['*', 'sns', 'multiple']; //, 'variant' => true), + private array $SNS = ['*', 'sns', 'multiple']; // , 'variant' => true), - /** - * @var NodeTypeManagerInterface - */ - private $ntm; + private NodeTypeManagerInterface $ntm; /** - * @var array + * @var string[] */ - protected $namespaces = []; + private array $namespaces = []; /** - * @var array + * @var NodeTypeDefinitionInterface[] */ - protected $nodeTypes = []; + private array $nodeTypes = []; - /** - * @param NodeTypeManagerInterface $ntm - */ public function __construct(NodeTypeManagerInterface $ntm) { $this->ntm = $ntm; @@ -88,10 +85,9 @@ public function __construct(NodeTypeManagerInterface $ntm) * * @param string $filename absolute path to the CND file to read * - * @return array with the namespaces map and the nodeTypes which is a - * hashmap of typename = > NodeTypeDefinitionInterface + * @return array{namespaces: string[], nodeTypes: array} */ - public function parseFile($filename) + public function parseFile(string $filename): array { $reader = new FileReader($filename); @@ -103,17 +99,19 @@ public function parseFile($filename) * * @param string $cnd string with CND content * - * @return array with the namespaces map and the nodeTypes which is a - * hashmap of typename = > NodeTypeDefinitionInterface + * @return array{namespaces: string[], nodeTypes: array} */ - public function parseString($cnd) + public function parseString(string $cnd): array { $reader = new BufferReader($cnd); return $this->parse($reader); } - private function parse(ReaderInterface $reader) + /** + * @return array{namespaces: string[], nodeTypes: array} + */ + private function parse(ReaderInterface $reader): array { $scanner = new GenericScanner(new DefaultScannerContextWithoutSpacesAndComments()); $this->tokenQueue = $scanner->scan($reader); @@ -130,7 +128,7 @@ private function parse(ReaderInterface $reader) return [ 'namespaces' => $this->namespaces, - 'nodeTypes' => $this->nodeTypes, + 'nodeTypes' => $this->nodeTypes, ]; } @@ -144,7 +142,7 @@ private function parse(ReaderInterface $reader) * Prefix ::= String * Uri ::= String */ - protected function parseNamespaceMapping() + private function parseNamespaceMapping(): void { $this->expectToken(Token::TK_SYMBOL, '<'); $prefix = $this->parseCndString(); @@ -164,7 +162,7 @@ protected function parseNamespaceMapping() * [NodeTypeAttribute {NodeTypeAttribute}] * {PropertyDef | ChildNodeDef} */ - protected function parseNodeType() + private function parseNodeType(): void { $nodeType = $this->ntm->createNodeTypeTemplate(); $this->parseNodeTypeName($nodeType); @@ -185,7 +183,7 @@ protected function parseNodeType() * * NodeTypeName ::= '[' String ']' */ - protected function parseNodeTypeName(NodeTypeTemplateInterface $nodeType) + private function parseNodeTypeName(NodeTypeTemplateInterface $nodeType): void { $this->expectToken(Token::TK_SYMBOL, '['); $name = $this->parseCndString(); @@ -202,7 +200,7 @@ protected function parseNodeTypeName(NodeTypeTemplateInterface $nodeType) * * Supertypes ::= '>' (StringList | '?') */ - protected function parseSupertypes(NodeTypeTemplateInterface $nodeType) + private function parseSupertypes(NodeTypeTemplateInterface $nodeType): void { $this->expectToken(Token::TK_SYMBOL, '>'); @@ -245,7 +243,7 @@ protected function parseSupertypes(NodeTypeTemplateInterface $nodeType) * Query ::= ('noquery' | 'nq') | ('query' | 'q' ) * PrimaryItem ::= ('primaryitem'| '!')(String | '?') */ - protected function parseNodeTypeAttributes(NodeTypeTemplateInterface $nodeType) + private function parseNodeTypeAttributes(NodeTypeTemplateInterface $nodeType): void { while (true) { if ($this->checkTokenIn(Token::TK_IDENTIFIER, $this->ORDERABLE)) { @@ -286,7 +284,7 @@ protected function parseNodeTypeAttributes(NodeTypeTemplateInterface $nodeType) * * {PropertyDef | ChildNodeDef} */ - protected function parseChildrenAndAttributes(NodeTypeTemplateInterface $nodeType) + private function parseChildrenAndAttributes(NodeTypeTemplateInterface $nodeType): void { while (true) { if ($this->checkToken(Token::TK_SYMBOL, '-')) { @@ -312,7 +310,7 @@ protected function parseChildrenAndAttributes(NodeTypeTemplateInterface $nodeTyp * [ValueConstraints] * PropertyName ::= '-' String */ - protected function parsePropDef(NodeTypeTemplateInterface $nodeType) + private function parsePropDef(NodeTypeTemplateInterface $nodeType): void { $this->expectToken(Token::TK_SYMBOL, '-'); @@ -350,7 +348,7 @@ protected function parsePropDef(NodeTypeTemplateInterface $nodeType) // Next token is '<' and two token later it's not '=', i.e. not 'tokenQueue->peek(); $next2 = $this->tokenQueue->peek(2); - if ($next1 && $next1->getData() === '<' && (!$next2 || $next2->getData() !== '=')) { + if ($next1 && '<' === $next1->getData() && (!$next2 || '=' !== $next2->getData())) { $this->parseValueConstraints($property); } } @@ -366,7 +364,7 @@ protected function parsePropDef(NodeTypeTemplateInterface $nodeType) * 'DECIMAL' | 'URI' | 'UNDEFINED' | '*' | * '?') ')' */ - protected function parsePropertyType(PropertyDefinitionTemplateInterface $property) + private function parsePropertyType(PropertyDefinitionTemplateInterface $property): void { $types = ['STRING', 'BINARY', 'LONG', 'DOUBLE', 'BOOLEAN', 'DATE', 'NAME', 'PATH', 'REFERENCE', 'WEAKREFERENCE', 'DECIMAL', 'URI', 'UNDEFINED', '*', '?', ]; @@ -390,7 +388,7 @@ protected function parsePropertyType(PropertyDefinitionTemplateInterface $proper * * DefaultValues ::= '=' (StringList | '?') */ - protected function parseDefaultValue(PropertyDefinitionTemplateInterface $property) + private function parseDefaultValue(PropertyDefinitionTemplateInterface $property): void { if ($this->checkAndExpectToken(Token::TK_SYMBOL, '?')) { $list = ['?']; @@ -408,7 +406,7 @@ protected function parseDefaultValue(PropertyDefinitionTemplateInterface $proper * * ValueConstraints ::= '<' (StringList | '?') */ - protected function parseValueConstraints(PropertyDefinitionTemplateInterface $property) + private function parseValueConstraints(PropertyDefinitionTemplateInterface $property): void { $this->expectToken(Token::TK_SYMBOL, '<'); @@ -475,7 +473,7 @@ protected function parseValueConstraints(PropertyDefinitionTemplateInterface $pr * NoFullText ::= ('nofulltext' | 'nof') ['?'] * NoQueryOrder ::= ('noqueryorder' | 'nqord') ['?'] */ - protected function parsePropertyAttributes(NodeTypeTemplateInterface $parentType, PropertyDefinitionTemplateInterface $property) + private function parsePropertyAttributes(NodeTypeTemplateInterface $parentType, PropertyDefinitionTemplateInterface $property): void { $opvSeen = false; while (true) { @@ -529,7 +527,7 @@ protected function parsePropertyAttributes(NodeTypeTemplateInterface $parentType * RequiredTypes ::= '(' (StringList | '?') ')' * DefaultType ::= '=' (String | '?') */ - protected function parseChildNodeDef(NodeTypeTemplateInterface $nodeType) + private function parseChildNodeDef(NodeTypeTemplateInterface $nodeType): void { $this->expectToken(Token::TK_SYMBOL, '+'); $childType = $this->ntm->createNodeDefinitionTemplate(); @@ -595,10 +593,10 @@ protected function parseChildNodeDef(NodeTypeTemplateInterface $nodeType) * 'IGNORE' | 'ABORT' | ('OPV' '?') * Sns ::= ('sns' | '*') ['?'] */ - protected function parseChildNodeAttributes( + private function parseChildNodeAttributes( NodeTypeTemplateInterface $parentType, NodeDefinitionTemplateInterface $childType - ) { + ): void { while (true) { if ($this->checkTokenIn(Token::TK_IDENTIFIER, $this->PRIMARY)) { $parentType->setPrimaryItemName($childType->getName()); @@ -627,9 +625,9 @@ protected function parseChildNodeAttributes( * * StringList ::= String {',' String} * - * @return array + * @return string[] */ - protected function parseCndStringList() + private function parseCndStringList(): array { $strings = []; @@ -659,10 +657,8 @@ protected function parseCndStringList() * Char ::= "\t" | "\r" | "\n" | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] * * TODO: check \n, \r, \t are valid in CND strings! - * - * @return string */ - protected function parseCndString() + private function parseCndString(): string { $string = ''; $lastType = null; @@ -678,7 +674,7 @@ protected function parseCndString() $type = $token->getType(); $data = $token->getData(); - if ($type === Token::TK_STRING) { + if (Token::TK_STRING === $type) { $string = substr($data, 1, -1); $this->tokenQueue->next(); @@ -686,13 +682,13 @@ protected function parseCndString() } // If it's not an identifier or a symbol allowed in a string, break - if ($type !== Token::TK_IDENTIFIER && $type !== Token::TK_SYMBOL - || ($type === Token::TK_SYMBOL && $data !== '_' && $data !== ':')) { + if (Token::TK_IDENTIFIER !== $type && Token::TK_SYMBOL !== $type + || (Token::TK_SYMBOL === $type && '_' !== $data && ':' !== $data)) { break; } // Detect spaces (an identifier cannot be followed by an identifier as it would have been read as a single token) - if ($type === Token::TK_IDENTIFIER && $lastType === Token::TK_IDENTIFIER) { + if (Token::TK_IDENTIFIER === $type && Token::TK_IDENTIFIER === $lastType) { break; } @@ -702,7 +698,7 @@ protected function parseCndString() $lastType = $type; } - if ($string === '') { + if ('' === $string) { throw new ParserException($this->tokenQueue, sprintf("Expected CND string, found '%s': ", $this->tokenQueue->peek()->getData())); } @@ -718,9 +714,9 @@ protected function parseCndString() * (('''Operator {','Operator}''') | '?') * Operator ::= '=' | '<>' | '<' | '<=' | '>' | '>=' | 'LIKE' * - * @return array + * @return array */ - protected function parseQueryOpsAttribute() + private function parseQueryOpsAttribute(): array { if ($this->checkAndExpectToken(Token::TK_SYMBOL, '?')) { // this denotes a variant, whatever that is @@ -736,12 +732,7 @@ protected function parseQueryOpsAttribute() return $ops; } - /** - * Parse a query operator. - * - * @return bool|string - */ - protected function parseQueryOperator() + private function parseQueryOperator(): bool|string { $token = $this->tokenQueue->peek(); $data = $token->getData(); @@ -752,10 +743,10 @@ protected function parseQueryOperator() switch ($data) { case '<': - $op = ($nextData === '>' ? '>=' : ($nextData === '=' ? '<=' : '<')); + $op = ('>' === $nextData ? '>=' : ('=' === $nextData ? '<=' : '<')); break; case '>': - $op = ($nextData === '=' ? '>=' : '>'); + $op = ('=' === $nextData ? '>=' : '>'); break; case '=': $op = '='; @@ -766,9 +757,9 @@ protected function parseQueryOperator() } // Consume the correct number of tokens - if ($op === 'LIKE' || strlen($op) === 1) { + if ('LIKE' === $op || 1 === strlen($op)) { $this->tokenQueue->next(); - } elseif (strlen($op) === 2) { + } elseif (2 === strlen($op)) { $this->tokenQueue->next(); $this->tokenQueue->next(); } diff --git a/src/PHPCR/Util/CND/Reader/BufferReader.php b/src/PHPCR/Util/CND/Reader/BufferReader.php index e38c00df..1a500d05 100644 --- a/src/PHPCR/Util/CND/Reader/BufferReader.php +++ b/src/PHPCR/Util/CND/Reader/BufferReader.php @@ -1,5 +1,7 @@ eofMarker = chr(1); $this->buffer = str_replace("\r\n", "\n", $buffer).$this->eofMarker; @@ -61,7 +36,7 @@ public function __construct($buffer) $this->reset(); } - public function reset() + public function reset(): void { $this->startPos = 0; @@ -70,51 +45,38 @@ public function reset() $this->nextCurLine = $this->nextCurCol = 1; } - /** - * @return string - */ - public function getEofMarker() + public function getEofMarker(): string { return $this->eofMarker; } - /** - * @return int - */ - public function getCurrentLine() + public function getCurrentLine(): int { return $this->curLine; } - /** - * @return int - */ - public function getCurrentColumn() + public function getCurrentColumn(): int { return $this->curCol; } /** * Return the literal delimited by start and end position. - * - * @return string */ - public function current() + public function current(): string { return substr($this->buffer, $this->startPos, $this->forwardPos - $this->startPos); } - public function currentChar() + public function currentChar(): string { return substr($this->buffer, $this->forwardPos, 1); } - /** - * @return bool - */ - public function isEof() + public function isEof(): bool { $currentChar = $this->currentChar(); + // substr after end of string returned false in PHP 5 and returns '' since PHP 7 return in_array($currentChar, [$this->getEofMarker(), false, ''], true) || $this->startPos > strlen($this->buffer) @@ -123,39 +85,37 @@ public function isEof() /** * Advance the forward position and return the literal delimited by start and end position. - * - * @return string */ - public function forward() + public function forward(): string { if ($this->forwardPos < strlen($this->buffer)) { - $this->forwardPos++; - $this->nextCurCol++; + ++$this->forwardPos; + ++$this->nextCurCol; } - if ($this->current() === "\n") { - $this->nextCurLine++; + if ("\n" === $this->current()) { + ++$this->nextCurLine; $this->nextCurCol = 1; } return $this->current(); } - public function forwardChar() + public function forwardChar(): string { $this->forward(); return $this->currentChar(); } - public function rewind() + public function rewind(): void { $this->forwardPos = $this->startPos; $this->nextCurLine = $this->curLine; $this->nextCurCol = $this->curCol; } - public function consume() + public function consume(): string { $current = $this->current(); diff --git a/src/PHPCR/Util/CND/Reader/FileReader.php b/src/PHPCR/Util/CND/Reader/FileReader.php index 353594d3..08d74353 100644 --- a/src/PHPCR/Util/CND/Reader/FileReader.php +++ b/src/PHPCR/Util/CND/Reader/FileReader.php @@ -1,5 +1,7 @@ * @author Nikola Petkanski */ -class FileReader extends BufferReader +final class FileReader extends BufferReader { - /** - * @var string - */ - protected $path; + private string $path; /** - * @param string $path - * * @throws \InvalidArgumentException */ - public function __construct($path) + public function __construct(string $path) { if (!file_exists($path)) { throw new \InvalidArgumentException(sprintf("Invalid file '%s'", $path)); @@ -31,10 +28,7 @@ public function __construct($path) parent::__construct(file_get_contents($path)); } - /** - * @return string - */ - public function getPath() + public function getPath(): string { return $this->path; } diff --git a/src/PHPCR/Util/CND/Reader/ReaderInterface.php b/src/PHPCR/Util/CND/Reader/ReaderInterface.php index 0f8b73eb..307c6f8e 100644 --- a/src/PHPCR/Util/CND/Reader/ReaderInterface.php +++ b/src/PHPCR/Util/CND/Reader/ReaderInterface.php @@ -1,5 +1,7 @@ context = $context; } - public function resetQueue() + public function resetQueue(): void { $this->queue = new TokenQueue(); } - /** - * @param Token $token - * - * @return Token|void - */ - public function applyFilters(Token $token) + public function applyFilters(Token $token): ?Token { foreach ($this->context->getTokenFilters() as $filter) { $token = $filter->filter($token); @@ -47,12 +41,12 @@ public function applyFilters(Token $token) return $token; } - protected function getQueue() + protected function getQueue(): TokenQueue { return $this->queue; } - protected function addToken(ReaderInterface $reader, Token $token) + protected function addToken(ReaderInterface $reader, Token $token): void { $token->setLine($reader->getCurrentLine()); $token->setRow($reader->getCurrentColumn()); diff --git a/src/PHPCR/Util/CND/Scanner/Context/DefaultScannerContext.php b/src/PHPCR/Util/CND/Scanner/Context/DefaultScannerContext.php index e9838026..8d90fa5a 100644 --- a/src/PHPCR/Util/CND/Scanner/Context/DefaultScannerContext.php +++ b/src/PHPCR/Util/CND/Scanner/Context/DefaultScannerContext.php @@ -1,5 +1,7 @@ blockCommentDelimiters[$startDelim] = $endDelim; } /** - * @return array + * @return string[] */ - public function getBlockCommentDelimiters() + public function getBlockCommentDelimiters(): array { return $this->blockCommentDelimiters; } - /** - * @param string $delim - */ - public function addLineCommentDelimiter($delim) + public function addLineCommentDelimiter(string $delim): void { $this->lineCommentDelimiters[] = $delim; } /** - * @return array + * @return string[] */ - public function getLineCommentDelimiters() + public function getLineCommentDelimiters(): array { return $this->lineCommentDelimiters; } - /** - * @param string $delim - */ - public function addStringDelimiter($delim) + public function addStringDelimiter(string $delim): void { - if (!in_array($delim, $this->stringDelimiters)) { + if (!in_array($delim, $this->stringDelimiters, true)) { $this->stringDelimiters[] = $delim; } } /** - * @return array + * @return string[] */ - public function getStringDelimiters() + public function getStringDelimiters(): array { return $this->stringDelimiters; } - /** - * @param string $symbol - */ - public function addSymbol($symbol) + public function addSymbol(string $symbol): void { - if (!in_array($symbol, $this->symbols)) { + if (!in_array($symbol, $this->symbols, true)) { $this->symbols[] = $symbol; } } /** - * @return array + * @return string[] */ - public function getSymbols() + public function getSymbols(): array { return $this->symbols; } - /** - * @param array $whitespace - */ - public function addWhitespace($whitespace) + public function addWhitespace(string $whitespace): void { - if (!in_array($whitespace, $this->whitespaces)) { + if (!in_array($whitespace, $this->whitespaces, true)) { $this->whitespaces[] = $whitespace; } } /** - * @return array + * @return string[] */ - public function getWhitespaces() + public function getWhitespaces(): array { return $this->whitespaces; } - /** - * @param TokenFilterInterface $filter - */ - public function addTokenFilter(TokenFilterInterface $filter) + public function addTokenFilter(TokenFilterInterface $filter): void { $this->tokenFilters[] = $filter; } @@ -154,7 +137,7 @@ public function addTokenFilter(TokenFilterInterface $filter) /** * @return TokenFilterInterface[] */ - public function getTokenFilters() + public function getTokenFilters(): array { return $this->tokenFilters; } diff --git a/src/PHPCR/Util/CND/Scanner/GenericScanner.php b/src/PHPCR/Util/CND/Scanner/GenericScanner.php index 76ccecd5..8161eb3a 100644 --- a/src/PHPCR/Util/CND/Scanner/GenericScanner.php +++ b/src/PHPCR/Util/CND/Scanner/GenericScanner.php @@ -1,5 +1,7 @@ resetQueue(); while (!$reader->isEof()) { - $tokenFound = false; - $tokenFound = $tokenFound || $this->consumeComments($reader); + $tokenFound = $this->consumeComments($reader); $tokenFound = $tokenFound || $this->consumeNewLine($reader); $tokenFound = $tokenFound || $this->consumeSpaces($reader); $tokenFound = $tokenFound || $this->consumeString($reader); @@ -54,12 +51,8 @@ public function scan(ReaderInterface $reader) /** * Detect and consume whitespaces. - * - * @param ReaderInterface $reader - * - * @return bool */ - protected function consumeSpaces(ReaderInterface $reader) + protected function consumeSpaces(ReaderInterface $reader): bool { if (in_array($reader->currentChar(), $this->context->getWhitespaces())) { $char = $reader->forwardChar(); @@ -80,18 +73,14 @@ protected function consumeSpaces(ReaderInterface $reader) /** * Detect and consume newlines. - * - * @param ReaderInterface $reader - * - * @return bool */ - protected function consumeNewLine(ReaderInterface $reader) + protected function consumeNewLine(ReaderInterface $reader): bool { - if ($reader->currentChar() === "\n") { + if ("\n" === $reader->currentChar()) { $token = new GenericToken(GenericToken::TK_NEWLINE, "\n"); $this->addToken($reader, $token); - while ($reader->forward() === "\n") { + while ("\n" === $reader->forward()) { $reader->consume(); $reader->forward(); } @@ -103,22 +92,13 @@ protected function consumeNewLine(ReaderInterface $reader) return false; } - /** - * Detect and consume strings. - * - * @param ReaderInterface $reader - * - * @throws ScannerException - * - * @return bool - */ - protected function consumeString(ReaderInterface $reader) + protected function consumeString(ReaderInterface $reader): bool { $curDelimiter = $reader->currentChar(); - if (in_array($curDelimiter, $this->context->getStringDelimiters())) { + if (in_array($curDelimiter, $this->context->getStringDelimiters(), true)) { $char = $reader->forwardChar(); while ($char !== $curDelimiter) { - if ($char === "\n") { + if ("\n" === $char) { throw new ScannerException($reader, 'Newline detected in string'); } @@ -135,14 +115,7 @@ protected function consumeString(ReaderInterface $reader) return false; } - /** - * Detect and consume comments. - * - * @param ReaderInterface $reader - * - * @return bool - */ - protected function consumeComments(ReaderInterface $reader) + protected function consumeComments(ReaderInterface $reader): bool { if ($this->consumeBlockComments($reader)) { return true; @@ -151,22 +124,14 @@ protected function consumeComments(ReaderInterface $reader) return $this->consumeLineComments($reader); } - /** - * Detect and consume block comments. - * - * @param ReaderInterface $reader - * - * @throws ScannerException - * - * @return bool - */ - protected function consumeBlockComments(ReaderInterface $reader) + protected function consumeBlockComments(ReaderInterface $reader): bool { $nextChar = $reader->currentChar(); foreach ($this->context->getBlockCommentDelimiters() as $beginDelim => $endDelim) { if ($nextChar === $beginDelim[0]) { + $beginDelimLength = strlen($beginDelim); // Lookup the start delimiter - for ($i = 1; $i <= strlen($beginDelim); $i++) { + for ($i = 1; $i <= $beginDelimLength; ++$i) { $reader->forward(); } if ($reader->current() === $beginDelim) { @@ -175,7 +140,8 @@ protected function consumeBlockComments(ReaderInterface $reader) while (!$reader->isEof()) { if ($nextChar === $endDelim[0]) { - for ($i = 1; $i <= strlen($endDelim); $i++) { + $endDelimLength = strlen($endDelim); + for ($i = 1; $i <= $endDelimLength; ++$i) { $reader->forward(); } @@ -204,26 +170,20 @@ protected function consumeBlockComments(ReaderInterface $reader) return false; } - /** - * Detect and consume line comments. - * - * @param ReaderInterface $reader - * - * @return bool - */ - protected function consumeLineComments(ReaderInterface $reader) + protected function consumeLineComments(ReaderInterface $reader): bool { $nextChar = $reader->currentChar(); foreach ($this->context->getLineCommentDelimiters() as $delimiter) { if ($delimiter && $nextChar === $delimiter[0]) { - for ($i = 1; $i <= strlen($delimiter); $i++) { + $delimiterLength = strlen($delimiter); + for ($i = 1; $i <= $delimiterLength; ++$i) { $reader->forward(); } if ($reader->current() === $delimiter) { // consume to end of line $char = $reader->currentChar(); - while (!$reader->isEof() && $char !== "\n") { + while (!$reader->isEof() && "\n" !== $char) { $char = $reader->forwardChar(); } $token = new GenericToken(GenericToken::TK_COMMENT, $reader->consume()); @@ -242,14 +202,7 @@ protected function consumeLineComments(ReaderInterface $reader) return false; } - /** - * Detect and consume identifiers. - * - * @param ReaderInterface $reader - * - * @return bool - */ - protected function consumeIdentifiers(ReaderInterface $reader) + protected function consumeIdentifiers(ReaderInterface $reader): bool { $nextChar = $reader->currentChar(); @@ -267,18 +220,11 @@ protected function consumeIdentifiers(ReaderInterface $reader) return false; } - /** - * Detect and consume symbols. - * - * @param ReaderInterface $reader - * - * @return bool - */ - protected function consumeSymbols(ReaderInterface $reader) + protected function consumeSymbols(ReaderInterface $reader): bool { $found = false; $nextChar = $reader->currentChar(); - while (in_array($nextChar, $this->context->getSymbols())) { + while (in_array($nextChar, $this->context->getSymbols(), true)) { $found = true; $token = new GenericToken(GenericToken::TK_SYMBOL, $nextChar); $this->addToken($reader, $token); diff --git a/src/PHPCR/Util/CND/Scanner/GenericToken.php b/src/PHPCR/Util/CND/Scanner/GenericToken.php index 735de8c7..9f88af81 100644 --- a/src/PHPCR/Util/CND/Scanner/GenericToken.php +++ b/src/PHPCR/Util/CND/Scanner/GenericToken.php @@ -1,5 +1,7 @@ 'Whitespace', + self::TK_NEWLINE => 'Newline', + self::TK_STRING => 'String', + self::TK_COMMENT => 'Comment', + self::TK_IDENTIFIER => 'Identifier', + self::TK_KEYWORD => 'Keyword', + self::TK_SYMBOL => 'Symbol', + default => 'Unknown', + }; } public function __toString() { - return sprintf("TOKEN(%s, '%s', %s, %s)", self::getTypeName($this->getType()), trim($this->data), $this->line, $this->row); + return sprintf("TOKEN(%s, '%s', %s, %s)", self::getTypeName($this->getType()), trim($this->getData()), $this->getLine(), $this->getRow()); } } diff --git a/src/PHPCR/Util/CND/Scanner/Token.php b/src/PHPCR/Util/CND/Scanner/Token.php index 80aebe61..10813282 100644 --- a/src/PHPCR/Util/CND/Scanner/Token.php +++ b/src/PHPCR/Util/CND/Scanner/Token.php @@ -1,5 +1,7 @@ type = $type; - $this->data = $data; - $this->line = $line; - $this->row = $row; + public function __construct( + private int $type = 0, + /** + * The token raw data. + */ + private string $data = '', + private int $line = 0, + private int $row = 0 + ) { } - /** - * @return string - */ - public function getData() + public function getData(): string { return $this->data; } - /** - * @return int - */ - public function getType() + public function getType(): int { return $this->type; } @@ -78,34 +41,22 @@ public function __toString() return sprintf("TOKEN(%s, '%s', %s, %s)", $this->type, trim($this->data), $this->line, $this->row); } - /** - * @param int $line - */ - public function setLine($line) + public function setLine(int $line): void { $this->line = $line; } - /** - * @return int - */ - public function getLine() + public function getLine(): int { return $this->line; } - /** - * @param int $row - */ - public function setRow($row) + public function setRow(int $row): void { $this->row = $row; } - /** - * @return int - */ - public function getRow() + public function getRow(): int { return $this->row; } diff --git a/src/PHPCR/Util/CND/Scanner/TokenFilter/NoCommentsFilter.php b/src/PHPCR/Util/CND/Scanner/TokenFilter/NoCommentsFilter.php index d2a898e0..08e0724c 100644 --- a/src/PHPCR/Util/CND/Scanner/TokenFilter/NoCommentsFilter.php +++ b/src/PHPCR/Util/CND/Scanner/TokenFilter/NoCommentsFilter.php @@ -1,5 +1,7 @@ filters[] = $filter; } - /** - * @param Token $token - * - * @return Token | null - */ - public function filter(Token $token) + public function filter(Token $token): ?Token { foreach ($this->filters as $filter) { $token = $filter->filter($token); if (!$token) { - return; + return null; } } diff --git a/src/PHPCR/Util/CND/Scanner/TokenFilter/TokenFilterInterface.php b/src/PHPCR/Util/CND/Scanner/TokenFilter/TokenFilterInterface.php index 6acf162f..d924f092 100644 --- a/src/PHPCR/Util/CND/Scanner/TokenFilter/TokenFilterInterface.php +++ b/src/PHPCR/Util/CND/Scanner/TokenFilter/TokenFilterInterface.php @@ -1,5 +1,7 @@ type = $tokenType; } - /** - * @param Token $token - * - * @return Token | null - */ - public function filter(Token $token) + public function filter(Token $token): ?Token { if ($token->getType() === $this->type) { - return; + return null; } return $token; diff --git a/src/PHPCR/Util/CND/Scanner/TokenQueue.php b/src/PHPCR/Util/CND/Scanner/TokenQueue.php index d1424d16..08bf6020 100644 --- a/src/PHPCR/Util/CND/Scanner/TokenQueue.php +++ b/src/PHPCR/Util/CND/Scanner/TokenQueue.php @@ -1,5 +1,7 @@ tokens = $tokens; } - public function add(Token $token) + public function add(Token $token): void { $this->tokens[] = $token; } - public function reset() + public function reset(): Token { return reset($this->tokens); } - public function isEof() + public function isEof(): bool { - return current($this->tokens) === false; + return false === current($this->tokens); } - public function peek($offset = 0) + public function peek($offset = 0): Token|false { if (!$offset) { return current($this->tokens); @@ -49,24 +54,23 @@ public function peek($offset = 0) return $this->tokens[key($this->tokens) + $offset]; } - public function get($count = 1) + public function get($count = 1): ?Token { $item = null; - for ($i = 1; $i <= $count; $i++) { + for ($i = 1; $i <= $count; ++$i) { $item = $this->peek(); $this->next(); } - return $item; + return $item ?: null; } - public function next() + public function next(): Token|false { return next($this->tokens); } - #[\ReturnTypeWillChange] - public function getIterator() + public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->tokens); } diff --git a/src/PHPCR/Util/CND/Writer/CndWriter.php b/src/PHPCR/Util/CND/Writer/CndWriter.php index 2ab75382..796f3997 100644 --- a/src/PHPCR/Util/CND/Writer/CndWriter.php +++ b/src/PHPCR/Util/CND/Writer/CndWriter.php @@ -1,5 +1,7 @@ hashmap of prefix => namespace uri */ - private $ns; - - /** @var array hashmap of prefix => namespace uri */ - private $namespaces = []; + private array $namespaces = []; - public function __construct(NamespaceRegistryInterface $ns) - { - $this->ns = $ns; + public function __construct( + private NamespaceRegistryInterface $ns + ) { } /** @@ -44,9 +43,9 @@ public function __construct(NamespaceRegistryInterface $ns) * @param NodeTypeTemplateInterface[] $nodeTypes * * @return string with declarations for all non-system namespaces and for - * all node types in that array. + * all node types in that array */ - public function writeString(array $nodeTypes) + public function writeString(array $nodeTypes): string { $cnd = ''; foreach ($nodeTypes as $nodeType) { @@ -63,7 +62,7 @@ public function writeString(array $nodeTypes) * Prefix ::= String * Uri ::= String */ - protected function writeNamespaces() + protected function writeNamespaces(): string { $ns = ''; foreach ($this->namespaces as $prefix => $uri) { @@ -73,12 +72,12 @@ protected function writeNamespaces() return $ns; } - private function checkNamespace($name) + private function checkNamespace($name): void { - if (false === strpos($name, ':')) { + if (!str_contains($name, ':')) { return; } - list($prefix) = explode(':', $name); + [$prefix] = explode(':', $name); // namespace registry will throw exception if namespace prefix not found $this->namespaces[$prefix] = "'".$this->ns->getURI($prefix)."'"; @@ -93,7 +92,7 @@ private function checkNamespace($name) * [NodeTypeAttribute {NodeTypeAttribute}] * {PropertyDef | ChildNodeDef} */ - protected function writeNodeType(NodeTypeDefinitionInterface $nodeType) + protected function writeNodeType(NodeTypeDefinitionInterface $nodeType): string { $this->checkNamespace($nodeType->getName()); $s = '['.$nodeType->getName().']'; @@ -120,9 +119,7 @@ protected function writeNodeType(NodeTypeDefinitionInterface $nodeType) if ($nodeType->getPrimaryItemName()) { $attributes .= 'primaryitem '.$nodeType->getPrimaryItemName().' '; } - if ($attributes) { - $s .= trim($attributes)."\n"; - } + $s .= trim($attributes)."\n"; $s .= $this->writeProperties($nodeType->getDeclaredPropertyDefinitions()); @@ -132,11 +129,9 @@ protected function writeNodeType(NodeTypeDefinitionInterface $nodeType) } /** - * @param PropertyDefinitionInterface[] $properties - * - * @return string + * @param PropertyDefinitionInterface[]|null $properties */ - private function writeProperties($properties) + private function writeProperties(?array $properties): string { if (null === $properties) { // getDeclaredPropertyDefinitions is allowed to return null on @@ -197,11 +192,9 @@ private function writeProperties($properties) } /** - * @param NodeDefinitionInterface[] $children - * - * @return string + * @param NodeDefinitionInterface[]|null $children */ - private function writeChildren($children) + private function writeChildren(?array $children): string { if (null === $children) { // getDeclaredChildNodeDefinitions is allowed to return null on @@ -237,7 +230,7 @@ private function writeChildren($children) if ($child->isProtected()) { $attributes .= 'protected '; } - if (OnParentVersionAction::COPY != $child->getOnParentVersion()) { + if (OnParentVersionAction::COPY !== $child->getOnParentVersion()) { $attributes .= OnParentVersionAction::nameFromValue($child->getOnParentVersion()).' '; } if ($child->allowsSameNameSiblings()) { diff --git a/src/PHPCR/Util/Console/Command/BaseCommand.php b/src/PHPCR/Util/Console/Command/BaseCommand.php index 5fdd56e7..756dab9a 100644 --- a/src/PHPCR/Util/Console/Command/BaseCommand.php +++ b/src/PHPCR/Util/Console/Command/BaseCommand.php @@ -1,17 +1,14 @@ getPhpcrHelper()->getSession(); } - /** - * @return PhpcrHelper - */ - protected function getPhpcrHelper() + protected function getPhpcrHelper(): PhpcrHelper { - return $this->getHelperSet()->get('phpcr'); - } - - /** - * @return PhpcrConsoleDumperHelper - */ - protected function getPhpcrConsoleDumperHelper() - { - return $this->getHelperSet()->get('phpcr_console_dumper'); - } - - /** - * Ask a question with the question helper or the dialog helper for symfony < 2.5 compatibility. - * - * @param InputInterface $input - * @param OutputInterface $output - * @param string $questionText - * @param string $default - * - * @return string - */ - protected function ask(InputInterface $input, OutputInterface $output, $questionText, $default = null) - { - if ($this->getHelperSet()->has('question')) { - $question = new Question($questionText, $default); - - return $this->getQuestionHelper()->ask($input, $output, $question); + $helper = $this->getHelper('phpcr'); + if (!$helper instanceof PhpcrHelper) { + throw new \RuntimeException('phpcr must be the PhpcrHelper'); } - return $this->getDialogHelper()->ask($output, $questionText, $default); + return $helper; } - /** - * Ask for confirmation with the question helper or the dialog helper for symfony < 2.5 compatibility. - * - * @param InputInterface $input - * @param OutputInterface $output - * @param string $questionText - * @param bool $default - * - * @return string - */ - protected function askConfirmation(InputInterface $input, OutputInterface $output, $questionText, $default = true) + protected function getPhpcrConsoleDumperHelper(): PhpcrConsoleDumperHelper { - if ($this->getHelperSet()->has('question')) { - $question = new ConfirmationQuestion($questionText, $default); - - return $this->getQuestionHelper()->ask($input, $output, $question); + $helper = $this->getHelper('phpcr_console_dumper'); + if (!$helper instanceof PhpcrConsoleDumperHelper) { + throw new \RuntimeException('phpcr_console_dumper must be the PhpcrConsoleDumperHelper'); } - return $this->getDialogHelper()->askConfirmation($output, $questionText, $default); + return $helper; } - private function getQuestionHelper(): QuestionHelper + protected function getQuestionHelper(): QuestionHelper { - return $this->getHelper('question'); - } + $helper = $this->getHelper('question'); + if (!$helper instanceof QuestionHelper) { + throw new \RuntimeException('question must be the QuestionHelper'); + } - private function getDialogHelper(): DialogHelper - { - return $this->getHelper('dialog'); + return $helper; } } diff --git a/src/PHPCR/Util/Console/Command/BaseNodeManipulationCommand.php b/src/PHPCR/Util/Console/Command/BaseNodeManipulationCommand.php index 9633e457..59f04bb0 100644 --- a/src/PHPCR/Util/Console/Command/BaseNodeManipulationCommand.php +++ b/src/PHPCR/Util/Console/Command/BaseNodeManipulationCommand.php @@ -1,5 +1,7 @@ addOption( 'set-prop', diff --git a/src/PHPCR/Util/Console/Command/NodeDumpCommand.php b/src/PHPCR/Util/Console/Command/NodeDumpCommand.php index 10cdf181..52b9e9a4 100644 --- a/src/PHPCR/Util/Console/Command/NodeDumpCommand.php +++ b/src/PHPCR/Util/Console/Command/NodeDumpCommand.php @@ -1,8 +1,9 @@ setName('phpcr:node:dump') @@ -42,27 +38,25 @@ protected function configure() ->setDescription('Dump subtrees of the content repository') ->setHelp( <<<'HERE' -The dump command recursively outputs the name of the node specified -by the identifier argument and its subnodes in a yaml-like style. + The dump command recursively outputs the name of the node specified + by the identifier argument and its subnodes in a yaml-like style. -If the props option is used the nodes properties are -displayed as yaml arrays. + If the props option is used the nodes properties are + displayed as yaml arrays. -By default the command filters out system nodes and properties (i.e. nodes and -properties with names starting with 'jcr:'), the --sys-nodes option -allows to turn this filter off. -HERE + By default the command filters out system nodes and properties (i.e. nodes and + properties with names starting with 'jcr:'), the --sys-nodes option + allows to turn this filter off. + HERE ); } /** - * {@inheritdoc} - * * @throws InvalidArgumentException - * @throws Exception + * @throws \Exception * @throws RepositoryException */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $session = $this->getPhpcrSession(); $dumperHelper = $this->getPhpcrConsoleDumperHelper(); @@ -79,7 +73,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $options['max_line_length'] = $input->getOption('max_line_length'); if (null !== $options['ref_format'] && !in_array($options['ref_format'], ['uuid', 'path'])) { - throw new Exception('The ref-format option must be set to either "path" or "uuid"'); + throw new \Exception('The ref-format option must be set to either "path" or "uuid"'); } $walker = $dumperHelper->getTreeWalker($output, $options); @@ -91,7 +85,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $node = $session->getNode($identifier); } - $walker->traverse($node, $input->getOption('depth')); + $walker->traverse($node, (int) $input->getOption('depth')); } catch (RepositoryException $e) { if ($e instanceof PathNotFoundException || $e instanceof ItemNotFoundException) { $output->writeln("Path '$identifier' does not exist"); diff --git a/src/PHPCR/Util/Console/Command/NodeMoveCommand.php b/src/PHPCR/Util/Console/Command/NodeMoveCommand.php index d0f3fd4a..e6b67303 100644 --- a/src/PHPCR/Util/Console/Command/NodeMoveCommand.php +++ b/src/PHPCR/Util/Console/Command/NodeMoveCommand.php @@ -1,5 +1,7 @@ setName('phpcr:node:move') @@ -31,23 +28,21 @@ protected function configure() ->setDescription('Moves a node from one path to another') ->setHelp( <<<'EOF' -This command simply moves a node from one path (the source path) -to another (the destination path), it can also be considered -as a rename command. + This command simply moves a node from one path (the source path) + to another (the destination path), it can also be considered + as a rename command. - $ php bin/phpcr phpcr:move /foobar /barfoo + $ php bin/phpcr phpcr:move /foobar /barfoo -Note that the parent node of the destination path must already exist. -EOF + Note that the parent node of the destination path must already exist. + EOF ); } /** - * {@inheritdoc} - * * @throws InvalidArgumentException */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $session = $this->getPhpcrSession(); diff --git a/src/PHPCR/Util/Console/Command/NodeRemoveCommand.php b/src/PHPCR/Util/Console/Command/NodeRemoveCommand.php index 280fb5a7..362df924 100644 --- a/src/PHPCR/Util/Console/Command/NodeRemoveCommand.php +++ b/src/PHPCR/Util/Console/Command/NodeRemoveCommand.php @@ -1,14 +1,15 @@ addOption('only-children', null, InputOption::VALUE_NONE, 'Use to only purge children of specified path') ->setHelp( <<<'EOF' -The phpcr:node:remove command will remove the given node or the -children of the given node according to the options given. + The phpcr:node:remove command will remove the given node or the + children of the given node according to the options given. -Remove specified node and its children: + Remove specified node and its children: - $ php bin/phpcr phpcr:node:remove /cms/content/blog + $ php bin/phpcr phpcr:node:remove /cms/content/blog -Remove only the children of the specified node + Remove only the children of the specified node - $ php bin/phpcr phpcr:node:remove /cms/content/blog --only-children -EOF + $ php bin/phpcr phpcr:node:remove /cms/content/blog --only-children + EOF ); } /** - * {@inheritdoc} - * * @throws CliInvalidArgumentException - * @throws InvalidArgumentException + * @throws \InvalidArgumentException */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $session = $this->getPhpcrSession(); @@ -69,7 +63,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if ('/' === $path) { // even if we have only children, this will not work as we would // try to remove system nodes. - throw new InvalidArgumentException( + throw new \InvalidArgumentException( 'Can not delete root node (path "/"), please use the '. 'workspace:purge command instead to purge the whole workspace.' ); @@ -87,13 +81,8 @@ protected function execute(InputInterface $input, OutputInterface $output) 'Are you sure you want to recursively delete the path "%s" '. 'from workspace "%s"'; } - - $force = $this->askConfirmation( - $input, - $output, - sprintf(''.$question.' Y/N ?', $path, $workspaceName), - false - ); + $confirmationQuestion = new ConfirmationQuestion(sprintf(''.$question.' Y/N ?', $path, $workspaceName), false); + $force = $this->getQuestionHelper()->ask($input, $output, $confirmationQuestion); } if (!$force) { @@ -107,7 +96,6 @@ protected function execute(InputInterface $input, OutputInterface $output) if ($onlyChildren) { $baseNode = $session->getNode($path, 0); - /** @var NodeInterface $childNode */ foreach ($baseNode->getNodes() as $childNode) { $childNodePath = $childNode->getPath(); $childNode->remove(); diff --git a/src/PHPCR/Util/Console/Command/NodeTouchCommand.php b/src/PHPCR/Util/Console/Command/NodeTouchCommand.php index 7ca3f0e8..7d554afd 100644 --- a/src/PHPCR/Util/Console/Command/NodeTouchCommand.php +++ b/src/PHPCR/Util/Console/Command/NodeTouchCommand.php @@ -1,5 +1,7 @@ setDescription('Create or modify a node') ->setHelp( <<<'HERE' -This command allows you to create or modify a node at the specified path. + This command allows you to create or modify a node at the specified path. -For example:: + For example:: - $ ./bin/phpcr phpcr:touch /foobar --type=my:nodetype --set-prop=foo=bar + $ ./bin/phpcr phpcr:touch /foobar --type=my:nodetype --set-prop=foo=bar -Will create the node "/foobar" and set (or create) the "foo" property -with a value of "bar". + Will create the node "/foobar" and set (or create) the "foo" property + with a value of "bar". -You can execute the command again to further modify the node. Here we add -the property "bar" and remove the property "foo". We also add the dump option -to output a string reperesentation of the node. + You can execute the command again to further modify the node. Here we add + the property "bar" and remove the property "foo". We also add the dump option + to output a string reperesentation of the node. - $ ./bin/phpcr phpcr:touch /foobar --type=my:nodetype --set-prop=bar=myvalue --remove-prop=foo --dump -HERE + $ ./bin/phpcr phpcr:touch /foobar --type=my:nodetype --set-prop=bar=myvalue --remove-prop=foo --dump + HERE ); } /** - * {@inheritdoc} - * * @throws InvalidArgumentException */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $helper = $this->getPhpcrHelper(); $session = $this->getPhpcrSession(); @@ -105,7 +100,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $nodeType )); - if ($nodeType != $type) { + if ($nodeType !== $type) { $output->writeln(sprintf( 'You have specified node type "%s" but the existing node is of type "%s"', $type, @@ -139,11 +134,11 @@ protected function execute(InputInterface $input, OutputInterface $output) } $helper->processNode($output, $node, [ - 'setProp' => $setProp, - 'removeProp' => $removeProp, - 'addMixins' => $addMixins, + 'setProp' => $setProp, + 'removeProp' => $removeProp, + 'addMixins' => $addMixins, 'removeMixins' => $removeMixins, - 'dump' => $dump, + 'dump' => $dump, ]); $session->save(); diff --git a/src/PHPCR/Util/Console/Command/NodeTypeListCommand.php b/src/PHPCR/Util/Console/Command/NodeTypeListCommand.php index 2f95fa56..88c6dbba 100644 --- a/src/PHPCR/Util/Console/Command/NodeTypeListCommand.php +++ b/src/PHPCR/Util/Console/Command/NodeTypeListCommand.php @@ -1,5 +1,7 @@ setName('phpcr:node-type:list') ->setDescription('List all available node types in the repository') ->setHelp( <<<'EOT' -This command lists all of the available node types and their subtypes -in the PHPCR repository. -EOT + This command lists all of the available node types and their subtypes + in the PHPCR repository. + EOT ); } - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $session = $this->getPhpcrSession(); $ntm = $session->getWorkspace()->getNodeTypeManager(); diff --git a/src/PHPCR/Util/Console/Command/NodeTypeRegisterCommand.php b/src/PHPCR/Util/Console/Command/NodeTypeRegisterCommand.php index 9cf78edd..7950ee4b 100644 --- a/src/PHPCR/Util/Console/Command/NodeTypeRegisterCommand.php +++ b/src/PHPCR/Util/Console/Command/NodeTypeRegisterCommand.php @@ -1,8 +1,9 @@ setName('phpcr:node-type:register') @@ -38,40 +36,38 @@ protected function configure() ->addOption('allow-update', null, InputOption::VALUE_NONE, 'Overwrite existig node type') ->setHelp( <<<'EOT' -Register node types in the PHPCR repository. + Register node types in the PHPCR repository. -This command allows to register node types in the repository that are defined -in a CND (Compact Namespace and Node Type Definition) file as defined in the JCR-283 -specification. + This command allows to register node types in the repository that are defined + in a CND (Compact Namespace and Node Type Definition) file as defined in the JCR-283 + specification. -Custom node types can be used to define the structure of content repository -nodes, like allowed properties and child nodes together with the namespaces -and their prefix used for the names of node types and properties. + Custom node types can be used to define the structure of content repository + nodes, like allowed properties and child nodes together with the namespaces + and their prefix used for the names of node types and properties. -This command allows you to specify multiple files and/or folders: + This command allows you to specify multiple files and/or folders: - $ php app/console phpcr:node-type:register /path/to/nodetype1.cnd /path/to/a/folder + $ php app/console phpcr:node-type:register /path/to/nodetype1.cnd /path/to/a/folder -When a folder is specified all files within the folder that have the .cnd -extension will be treated as node definition files. + When a folder is specified all files within the folder that have the .cnd + extension will be treated as node definition files. -If you use --allow-update existing node type definitions will be overwritten -in the repository. -EOT + If you use --allow-update existing node type definitions will be overwritten + in the repository. + EOT ); } /** - * {@inheritdoc} - * - * @throws InvalidArgumentException + * @throws \InvalidArgumentException */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $definitions = $input->getArgument('cnd-file'); - if (count($definitions) == 0) { - throw new InvalidArgumentException('At least one definition (i.e. file or folder) must be specified'); + if (0 === count($definitions)) { + throw new \InvalidArgumentException('At least one definition (i.e. file or folder) must be specified'); } $allowUpdate = $input->getOption('allow-update'); @@ -84,7 +80,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $cnd = file_get_contents($filePath); $this->updateFromCnd($output, $session, $cnd, $allowUpdate); $output->writeln(sprintf('Node type definition: %s', $filePath)); - $count++; + ++$count; } $output->writeln(sprintf('%d node definition(s) registered', $count)); @@ -98,11 +94,11 @@ protected function execute(InputInterface $input, OutputInterface $output) * @param OutputInterface $output the console output stream * @param SessionInterface $session the PHPCR session to talk to * @param string $cnd the compact namespace and node type definition in string form - * @param bool $allowUpdate whether to allow updating existing node types. + * @param bool $allowUpdate whether to allow updating existing node types * * @throws RepositoryException on other errors */ - protected function updateFromCnd(OutputInterface $output, SessionInterface $session, $cnd, $allowUpdate) + protected function updateFromCnd(OutputInterface $output, SessionInterface $session, string $cnd, bool $allowUpdate): void { $ntm = $session->getWorkspace()->getNodeTypeManager(); @@ -123,13 +119,13 @@ protected function updateFromCnd(OutputInterface $output, SessionInterface $sess * Return a list of node type definition file paths from * the given definition files or folders. * - * @param array $definitions List of files of folders + * @param string[] $definitions List of files or folders * - * @throws InvalidArgumentException + * @return string[] list of available node type definition files * - * @return array Array of full paths to all the type node definition files. + * @throws \InvalidArgumentException */ - protected function getFilePaths($definitions) + protected function getFilePaths(array $definitions): array { $filePaths = []; @@ -145,7 +141,7 @@ protected function getFilePaths($definitions) $filePath = sprintf('%s/%s', $definition, $file); if (!is_readable($filePath)) { - throw new InvalidArgumentException( + throw new \InvalidArgumentException( sprintf("Node type definition file '%s' does not have read permissions.", $file) ); } @@ -154,7 +150,7 @@ protected function getFilePaths($definitions) } } else { if (!file_exists($definition)) { - throw new InvalidArgumentException( + throw new \InvalidArgumentException( sprintf("Node type definition file / folder '%s' does not exist.", $definition) ); } @@ -166,8 +162,8 @@ protected function getFilePaths($definitions) return $filePaths; } - protected function fileIsNodeType($filename) + protected function fileIsNodeType(string $filename): bool { - return substr($filename, -4) === '.cnd'; + return str_ends_with($filename, '.cnd'); } } diff --git a/src/PHPCR/Util/Console/Command/NodesUpdateCommand.php b/src/PHPCR/Util/Console/Command/NodesUpdateCommand.php index 50aa22d0..eeb4d94f 100644 --- a/src/PHPCR/Util/Console/Command/NodesUpdateCommand.php +++ b/src/PHPCR/Util/Console/Command/NodesUpdateCommand.php @@ -1,14 +1,16 @@ setDescription('Command to manipulate the nodes in the workspace.') ->setHelp( <<phpcr:nodes:update can manipulate the properties of nodes -found using the given query. + The phpcr:nodes:update can manipulate the properties of nodes + found using the given query. -For example, to set the property foo to bar on all unstructured nodes: + For example, to set the property foo to bar on all unstructured nodes: - php bin/phpcr phpcr:nodes:update --query="SELECT * FROM [nt:unstructured]" --set-prop=foo=bar + php bin/phpcr phpcr:nodes:update --query="SELECT * FROM [nt:unstructured]" --set-prop=foo=bar -Or to update only nodes matching a certain criteria: + Or to update only nodes matching a certain criteria: - php bin/phpcr phpcr:nodes:update \ - --query="SELECT * FROM [nt:unstructured] WHERE [phpcr:class]=\"Some\\Class\\Here\"" \ - --add-mixin=mix:mimetype + php bin/phpcr phpcr:nodes:update \ + --query="SELECT * FROM [nt:unstructured] WHERE [phpcr:class]=\"Some\\Class\\Here\"" \ + --add-mixin=mix:mimetype -The options for manipulating nodes are the same as with the -node:touch command and -can be repeated to update multiple properties. + The options for manipulating nodes are the same as with the + node:touch command and + can be repeated to update multiple properties. -If you have an advanced use case you can use the --apply-closure option: + If you have an advanced use case you can use the --apply-closure option: - php bin/phpcr phpcr:nodes:update \ - --query="SELECT * FROM [nt:unstructured] WHERE [phpcr:class]=\"Some\\Class\\Here\"" \ - --apply-closure="\\\$session->doSomething(); \\\$node->setProperty('foo', 'bar');" + php bin/phpcr phpcr:nodes:update \ + --query="SELECT * FROM [nt:unstructured] WHERE [phpcr:class]=\"Some\\Class\\Here\"" \ + --apply-closure="\\\$session->doSomething(); \\\$node->setProperty('foo', 'bar');" -For each node in the result set, the closure will be passed the current -PHPCR\SessionInterface implementation and the node (PHPCR\NodeInterface) as \$session and \$node. -HERE + For each node in the result set, the closure will be passed the current + PHPCR\SessionInterface implementation and the node (PHPCR\NodeInterface) as \$session and \$node. + HERE ); } /** - * {@inheritdoc} - * * @throws CliInvalidArgumentException - * @throws InvalidArgumentException + * @throws \InvalidArgumentException */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $query = $input->getOption('query'); $queryLanguage = strtoupper($input->getOption('query-language')); @@ -105,13 +100,13 @@ protected function execute(InputInterface $input, OutputInterface $output) $session = $this->getPhpcrSession(); if (!$query) { - throw new InvalidArgumentException( + throw new \InvalidArgumentException( 'You must provide a SELECT query, e.g. --query="SELECT * FROM [nt:unstructured]"' ); } - if (strtoupper(substr($query, 0, 6)) !== 'SELECT') { - throw new InvalidArgumentException("Query doesn't look like a SELECT query: '$query'"); + if (0 !== stripos($query, 'SELECT')) { + throw new \InvalidArgumentException("Query doesn't look like a SELECT query: '$query'"); } $query = $helper->createQuery($queryLanguage, $query); @@ -136,14 +131,14 @@ protected function execute(InputInterface $input, OutputInterface $output) $node = $row->getNode(); $helper->processNode($output, $node, [ - 'setProp' => $setProp, - 'removeProp' => $removeProp, - 'addMixins' => $addMixins, - 'removeMixins' => $removeMixins, + 'setProp' => $setProp, + 'removeProp' => $removeProp, + 'addMixins' => $addMixins, + 'removeMixins' => $removeMixins, 'applyClosures' => $applyClosures, ]); - $persistIn--; + --$persistIn; if (0 === $persistIn) { $output->writeln('Saving nodes processed so far...'); $session->save(); @@ -158,17 +153,15 @@ protected function execute(InputInterface $input, OutputInterface $output) return 0; } - /** - * @return bool Whether to execute the action or not. - */ - private function shouldExecute(InputInterface $input, OutputInterface $output, QueryResultInterface $result) + private function shouldExecute(InputInterface $input, OutputInterface $output, QueryResultInterface $result): bool { - $response = strtoupper($this->ask($input, $output, sprintf( + $question = new ConfirmationQuestion(sprintf( 'About to update %d nodes. Enter "Y" to continue, "N" to cancel or "L" to list.', count($result->getRows()) - ))); + )); - if ($response === 'L') { + $response = $this->getQuestionHelper()->ask($input, $output, $question); + if ('L' === $response) { /** @var RowInterface $row */ foreach ($result as $i => $row) { $output->writeln(sprintf(' - [%d] %s', $i, $row->getPath())); @@ -177,11 +170,11 @@ private function shouldExecute(InputInterface $input, OutputInterface $output, Q return $this->shouldExecute($input, $output, $result); } - if ($response === 'N') { + if ('N' === $response) { return false; } - if ($response === 'Y') { + if ('Y' === $response) { return true; } diff --git a/src/PHPCR/Util/Console/Command/WorkspaceCreateCommand.php b/src/PHPCR/Util/Console/Command/WorkspaceCreateCommand.php index c0ac8a6e..07f6c554 100644 --- a/src/PHPCR/Util/Console/Command/WorkspaceCreateCommand.php +++ b/src/PHPCR/Util/Console/Command/WorkspaceCreateCommand.php @@ -1,5 +1,7 @@ setName('phpcr:workspace:create') @@ -35,17 +34,14 @@ protected function configure() ->setDescription('Create a workspace in the configured repository') ->setHelp( <<<'EOT' -The workspace:create command creates a workspace with the specified name. -It will fail if a workspace with that name already exists or if the repository implementation -does not support the workspace creation operation. -EOT + The workspace:create command creates a workspace with the specified name. + It will fail if a workspace with that name already exists or if the repository implementation + does not support the workspace creation operation. + EOT ); } - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $session = $this->getPhpcrSession(); @@ -64,7 +60,7 @@ protected function execute(InputInterface $input, OutputInterface $output) return 1; } - if (in_array($workspaceName, $workspace->getAccessibleWorkspaceNames())) { + if (in_array($workspaceName, $workspace->getAccessibleWorkspaceNames(), true)) { $output->writeln( sprintf('This repository already has a workspace called "%s"', $workspaceName) ); diff --git a/src/PHPCR/Util/Console/Command/WorkspaceDeleteCommand.php b/src/PHPCR/Util/Console/Command/WorkspaceDeleteCommand.php index 9200fe66..23662768 100644 --- a/src/PHPCR/Util/Console/Command/WorkspaceDeleteCommand.php +++ b/src/PHPCR/Util/Console/Command/WorkspaceDeleteCommand.php @@ -1,5 +1,7 @@ setName('phpcr:workspace:delete') @@ -29,18 +29,15 @@ protected function configure() ->setDescription('Delete a workspace from the configured repository') ->setHelp( <<<'EOT' -The workspace:delete command deletes the workspace with the specified name if it -exists. If the workspace with that name does not yet exist, the command will not fail. -However, if the workspace does exist but the repository implementation does not support -the delete operation, the command will fail. -EOT + The workspace:delete command deletes the workspace with the specified name if it + exists. If the workspace with that name does not yet exist, the command will not fail. + However, if the workspace does exist but the repository implementation does not support + the delete operation, the command will fail. + EOT ); } - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $session = $this->getPhpcrSession(); @@ -67,10 +64,11 @@ protected function execute(InputInterface $input, OutputInterface $output) $force = $input->getOption('force'); if (!$force) { - $force = $this->askConfirmation($input, $output, sprintf( + $confirmationQuestion = new ConfirmationQuestion(sprintf( 'Are you sure you want to delete workspace "%s" Y/N ?', $workspaceName ), false); + $force = $this->getQuestionHelper()->ask($input, $output, $confirmationQuestion); } if (!$force) { $output->writeln('Aborted'); diff --git a/src/PHPCR/Util/Console/Command/WorkspaceExportCommand.php b/src/PHPCR/Util/Console/Command/WorkspaceExportCommand.php index 5708e79b..25009189 100644 --- a/src/PHPCR/Util/Console/Command/WorkspaceExportCommand.php +++ b/src/PHPCR/Util/Console/Command/WorkspaceExportCommand.php @@ -1,5 +1,7 @@ setDescription('Export nodes from the repository, either to the JCR system view format or the document view format') ->setHelp( <<<'EOF' -The export command uses the PHPCR SessionInterface::exportSystemView -method to export parts of the repository into an XML document. + The export command uses the PHPCR SessionInterface::exportSystemView + method to export parts of the repository into an XML document. -If the path option is set, given path is exported. -Otherwise the entire repository is exported. -EOF + If the path option is set, given path is exported. + Otherwise the entire repository is exported. + EOF ); } - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $session = $this->getPhpcrSession(); $repo = $session->getRepository(); @@ -64,7 +60,7 @@ protected function execute(InputInterface $input, OutputInterface $output) return 2; } - $session->exportSystemView($path, $stream, $input->getOption('skip_binary') === 'yes', $input->getOption('recurse') === 'no'); + $session->exportSystemView($path, $stream, 'yes' === $input->getOption('skip_binary'), 'no' === $input->getOption('recurse')); $output->writeln(sprintf( 'Successfully exported workspace "%s", path "%s" to file "%s".', diff --git a/src/PHPCR/Util/Console/Command/WorkspaceImportCommand.php b/src/PHPCR/Util/Console/Command/WorkspaceImportCommand.php index 4b6578db..b9b0047c 100644 --- a/src/PHPCR/Util/Console/Command/WorkspaceImportCommand.php +++ b/src/PHPCR/Util/Console/Command/WorkspaceImportCommand.php @@ -1,5 +1,7 @@ ImportUUIDBehaviorInterface::IMPORT_UUID_CREATE_NEW, - 'remove' => ImportUUIDBehaviorInterface::IMPORT_UUID_COLLISION_REMOVE_EXISTING, + public const UUID_BEHAVIOR = [ + 'new' => ImportUUIDBehaviorInterface::IMPORT_UUID_CREATE_NEW, + 'remove' => ImportUUIDBehaviorInterface::IMPORT_UUID_COLLISION_REMOVE_EXISTING, 'replace' => ImportUUIDBehaviorInterface::IMPORT_UUID_COLLISION_REPLACE_EXISTING, - 'throw' => ImportUUIDBehaviorInterface::IMPORT_UUID_COLLISION_THROW, + 'throw' => ImportUUIDBehaviorInterface::IMPORT_UUID_COLLISION_THROW, ]; - /** - * {@inheritdoc} - */ - protected function configure() + protected function configure(): void { parent::configure(); @@ -39,33 +38,30 @@ protected function configure() ->setDescription('Import xml data into the repository, either in JCR system view format or arbitrary xml') ->setHelp( <<<'EOF' -The import command uses the PHPCR SessionInterface::importXml method -to import an XML document into the repository. If the document is in the JCR -system view format, it is interpreted according to the spec, otherwise it is -treated as document view format, meaning XML elements are translated to nodes -and XML attributes into properties. - -If the parentpath option is set, the document is imported to that -path. Otherwise the document is imported at the repository root. - -The optional uuid-behavior option describes how UUIDs should be -handled. The following options are available: - -* new recreate a new uuid for each imported node; -* remove on collision, remove the old node from the repository and - put the imported data in the tree; -* replace on collision, replace the existing node with the one being - imported. All children of the imported node also go to the new path; -* throw throw an exception on uuid collision. - -EOF + The import command uses the PHPCR SessionInterface::importXml method + to import an XML document into the repository. If the document is in the JCR + system view format, it is interpreted according to the spec, otherwise it is + treated as document view format, meaning XML elements are translated to nodes + and XML attributes into properties. + + If the parentpath option is set, the document is imported to that + path. Otherwise the document is imported at the repository root. + + The optional uuid-behavior option describes how UUIDs should be + handled. The following options are available: + + * new recreate a new uuid for each imported node; + * remove on collision, remove the old node from the repository and + put the imported data in the tree; + * replace on collision, replace the existing node with the one being + imported. All children of the imported node also go to the new path; + * throw throw an exception on uuid collision. + + EOF ); } - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $filename = $input->getArgument('filename'); $parentPath = $input->getOption('parentpath'); diff --git a/src/PHPCR/Util/Console/Command/WorkspaceListCommand.php b/src/PHPCR/Util/Console/Command/WorkspaceListCommand.php index 3165f8b9..3a5d6317 100644 --- a/src/PHPCR/Util/Console/Command/WorkspaceListCommand.php +++ b/src/PHPCR/Util/Console/Command/WorkspaceListCommand.php @@ -1,5 +1,7 @@ setName('phpcr:workspace:list') ->setDescription('List all available workspaces in the configured repository') ->setHelp( <<<'EOT' -The workspace:list command lists all avaialable workspaces. -EOT + The workspace:list command lists all avaialable workspaces. + EOT ); } - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $session = $this->getPhpcrSession(); diff --git a/src/PHPCR/Util/Console/Command/WorkspacePurgeCommand.php b/src/PHPCR/Util/Console/Command/WorkspacePurgeCommand.php index c8c8f81a..ac2dc07d 100644 --- a/src/PHPCR/Util/Console/Command/WorkspacePurgeCommand.php +++ b/src/PHPCR/Util/Console/Command/WorkspacePurgeCommand.php @@ -1,11 +1,14 @@ addOption('force', null, InputOption::VALUE_NONE, 'Use to bypass the confirmation dialog') ->setHelp( <<<'EOF' -The phpcr:workspace:purge command removes all nodes except the -system nodes and all non-system properties of the root node from the workspace. -EOF + The phpcr:workspace:purge command removes all nodes except the + system nodes and all non-system properties of the root node from the workspace. + EOF ); } - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $session = $this->getPhpcrSession(); $force = $input->getOption('force'); $workspaceName = $session->getWorkspace()->getName(); if (!$force) { - $force = $this->askConfirmation($input, $output, sprintf( + $confirmationQuestion = new ConfirmationQuestion(sprintf( 'Are you sure you want to purge workspace "%s" Y/N ?', $workspaceName ), false); + $force = $this->getQuestionHelper()->ask($input, $output, $confirmationQuestion); } if (!$force) { diff --git a/src/PHPCR/Util/Console/Command/WorkspaceQueryCommand.php b/src/PHPCR/Util/Console/Command/WorkspaceQueryCommand.php index f4d7fc15..2b9944e8 100644 --- a/src/PHPCR/Util/Console/Command/WorkspaceQueryCommand.php +++ b/src/PHPCR/Util/Console/Command/WorkspaceQueryCommand.php @@ -1,5 +1,7 @@ setHelp('The query command executes a JCR query statement on the content repository'); } - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $sql = $input->getArgument('query'); $language = $input->getOption('language'); diff --git a/src/PHPCR/Util/Console/Helper/PhpcrConsoleDumperHelper.php b/src/PHPCR/Util/Console/Helper/PhpcrConsoleDumperHelper.php index d7d3cdbd..e09443ed 100644 --- a/src/PHPCR/Util/Console/Helper/PhpcrConsoleDumperHelper.php +++ b/src/PHPCR/Util/Console/Helper/PhpcrConsoleDumperHelper.php @@ -1,5 +1,7 @@ false, - 'ref_format' => 'uuid', - 'show_props' => false, + 'dump_uuids' => false, + 'ref_format' => 'uuid', + 'show_props' => false, 'show_sys_nodes' => false, ], $options); @@ -43,10 +45,7 @@ public function getTreeWalker(OutputInterface $output, $options) return $treeWalker; } - /** - * {@inheritdoc} - */ - public function getName() + public function getName(): string { return 'phpcr_console_dumper'; } diff --git a/src/PHPCR/Util/Console/Helper/PhpcrHelper.php b/src/PHPCR/Util/Console/Helper/PhpcrHelper.php index edb6edc4..f447df5b 100644 --- a/src/PHPCR/Util/Console/Helper/PhpcrHelper.php +++ b/src/PHPCR/Util/Console/Helper/PhpcrHelper.php @@ -1,10 +1,11 @@ session = $session; } - /** - * Get the session. - * - * @return SessionInterface - */ - public function getSession() + public function getSession(): SessionInterface { return $this->session; } - /** - * {@inheritdoc} - */ - public function getName() + public function getName(): string { return 'phpcr'; } @@ -57,19 +40,19 @@ public function getName() * * Provides common processing for both touch and update commands. * - * @param OutputInterface $output used for status updates. - * @param NodeInterface $node the node to manipulate. - * @param array $operations to execute on that node. + * @param OutputInterface $output used for status updates + * @param NodeInterface $node the node to manipulate + * @param array $operations to execute on that node */ - public function processNode(OutputInterface $output, NodeInterface $node, array $operations) + public function processNode(OutputInterface $output, NodeInterface $node, array $operations): void { $operations = array_merge([ - 'setProp' => [], - 'removeProp' => [], - 'addMixins' => [], - 'removeMixins' => [], + 'setProp' => [], + 'removeProp' => [], + 'addMixins' => [], + 'removeMixins' => [], 'applyClosures' => [], - 'dump' => false, + 'dump' => false, ], $operations); foreach ($operations['setProp'] as $set) { @@ -115,7 +98,7 @@ public function processNode(OutputInterface $output, NodeInterface $node, array ); } else { $closureString = $closure; - $closure = function (SessionInterface $session, NodeInterface $node) use ($closureString) { + $closure = function (SessionInterface $session, NodeInterface $node) use ($closureString): void { eval($closureString); }; $output->writeln(sprintf( @@ -129,7 +112,6 @@ public function processNode(OutputInterface $output, NodeInterface $node, array if ($operations['dump']) { $output->writeln('Node dump: '); - /** @var PropertyInterface $property */ foreach ($node->getProperties() as $property) { $value = $property->getValue(); if (!is_string($value)) { @@ -150,38 +132,33 @@ public function processNode(OutputInterface $output, NodeInterface $node, array * * @param string $language Language type - SQL, SQL2 * @param string $sql JCR Query string - * - * @return \PHPCR\Query\QueryInterface */ - public function createQuery($language, $sql) + public function createQuery(string $language, string $sql): QueryInterface { $language = $this->validateQueryLanguage($language); $session = $this->getSession(); $qm = $session->getWorkspace()->getQueryManager(); - $query = $qm->createQuery($sql, $language); - return $query; + return $qm->createQuery($sql, $language); } /** * Check if this is a supported query language. * - * @param string $language Language name. - * - * @throws \Exception if the language is not supported. + * @throws \Exception if the language is not supported */ - protected function validateQueryLanguage($language) + protected function validateQueryLanguage(string $language): string { $qm = $this->getSession()->getWorkspace()->getQueryManager(); $langs = $qm->getSupportedQueryLanguages(); foreach ($langs as $lang) { - if (strtoupper($lang) === strtoupper($language)) { + if (0 === strcasecmp($lang, $language)) { return $lang; } } - throw new Exception(sprintf( + throw new \Exception(sprintf( 'Query language "%s" not supported, available query languages: %s', $language, implode(',', $langs) diff --git a/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperItemVisitor.php b/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperItemVisitor.php index ddd16233..ecdd293b 100644 --- a/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperItemVisitor.php +++ b/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperItemVisitor.php @@ -1,5 +1,7 @@ output = $output; + public function __construct( + protected OutputInterface $output + ) { } /** * Set the current depth level for indention. - * - * @param int $level */ - public function setLevel($level) + public function setLevel(int $level): void { $this->level = $level; } diff --git a/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperNodeVisitor.php b/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperNodeVisitor.php index c64438b3..e1f81530 100644 --- a/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperNodeVisitor.php +++ b/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperNodeVisitor.php @@ -1,8 +1,9 @@ identifiers = $identifiers; } - /** - * If to show the full path or not. - * - * @param bool $showFullPath - */ - public function setShowFullPath($showFullPath) + public function setShowFullPath(bool $showFullPath): void { $this->showFullPath = $showFullPath; } @@ -51,17 +42,15 @@ public function setShowFullPath($showFullPath) /** * Print information about the visited node. * - * @param ItemInterface $item the node to visit - * - * @throws Exception + * @throws \Exception */ - public function visit(ItemInterface $item) + public function visit(ItemInterface $item): void { if (!$item instanceof NodeInterface) { - throw new Exception('Internal error: did not expect to visit a non-node object: '.get_class($item)); + throw new \Exception('Internal error: did not expect to visit a non-node object: '.$item::class); } - if ($item->getDepth() === 0) { + if (0 === $item->getDepth()) { $name = 'ROOT'; } elseif ($this->showFullPath) { $name = $item->getPath(); diff --git a/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperPropertyVisitor.php b/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperPropertyVisitor.php index 63ccbc7b..4a4f41c3 100644 --- a/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperPropertyVisitor.php +++ b/src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperPropertyVisitor.php @@ -1,8 +1,9 @@ $options */ - private $refFormat; - - /** - * Instantiate property visitor. - * - * @param OutputInterface $output - * @param array $options - */ - public function __construct(OutputInterface $output, $options = []) + public function __construct(OutputInterface $output, array $options = []) { $options = array_merge([ 'max_line_length' => 120, - 'ref_format' => 'uuid', + 'ref_format' => 'uuid', ], $options); parent::__construct($output); - $this->maxLineLength = $options['max_line_length']; - $this->refFormat = $options['ref_format']; + $this->maxLineLength = (int) $options['max_line_length']; + $this->refFormat = (string) $options['ref_format']; } /** * Print information about this property. * - * @param ItemInterface $item the property to visit - * - * @throws Exception + * @throws \Exception */ - public function visit(ItemInterface $item) + public function visit(ItemInterface $item): void { if (!$item instanceof PropertyInterface) { - throw new Exception(sprintf('Internal error: did not expect to visit a non-property object: %s', is_object($item) ? get_class($item) : $item)); + throw new \Exception(sprintf('Internal error: did not expect to visit a non-property object: %s', $item::class)); } $value = $item->getString(); @@ -79,10 +65,10 @@ public function visit(ItemInterface $item) if (in_array($item->getType(), [ PropertyType::WEAKREFERENCE, PropertyType::REFERENCE, - ])) { + ], true)) { $referenceStrings = []; - if ('path' == $this->refFormat) { + if ('path' === $this->refFormat) { $references = (array) $item->getValue(); foreach ($references as $reference) { diff --git a/src/PHPCR/Util/Console/Helper/TreeDumper/SystemNodeFilter.php b/src/PHPCR/Util/Console/Helper/TreeDumper/SystemNodeFilter.php index 51c1cf67..64a7e796 100644 --- a/src/PHPCR/Util/Console/Helper/TreeDumper/SystemNodeFilter.php +++ b/src/PHPCR/Util/Console/Helper/TreeDumper/SystemNodeFilter.php @@ -1,5 +1,7 @@ getRootNode(); @@ -82,18 +84,16 @@ public static function createPath(SessionInterface $session, $path) * * @see isSystemItem */ - public static function purgeWorkspace(SessionInterface $session) + public static function purgeWorkspace(SessionInterface $session): void { $root = $session->getRootNode(); - /** @var PropertyInterface $property */ foreach ($root->getProperties() as $property) { if (!self::isSystemItem($property)) { $property->remove(); } } - /** @var NodeInterface $node */ foreach ($root->getNodes() as $node) { if (!self::isSystemItem($node)) { $node->remove(); @@ -101,39 +101,21 @@ public static function purgeWorkspace(SessionInterface $session) } } - /** - * Kept as alias of purgeWorkspace for BC compatibility. - * - * @param SessionInterface $session - * - * @throws RepositoryException - * - * @deprecated - */ - public static function deleteAllNodes(SessionInterface $session) - { - self::purgeWorkspace($session); - } - /** * Determine whether this item is to be considered a system item that you * usually want to hide and that should not be removed when purging the * repository. * - * @param ItemInterface $item - * * @throws RepositoryException - * - * @return bool true if $item is a system item, false otherwise */ - public static function isSystemItem(ItemInterface $item) + public static function isSystemItem(ItemInterface $item): bool { if ($item->getDepth() > 1) { return false; } $name = $item->getName(); - return strpos($name, 'jcr:') === 0 || strpos($name, 'rep:') === 0; + return str_starts_with($name, 'jcr:') || str_starts_with($name, 'rep:'); } /** @@ -142,19 +124,20 @@ public static function isSystemItem(ItemInterface $item) * This method only checks for valid namespaces. All other exceptions must * be thrown by the addNodeAutoNamed implementation. * - * @param string[] $usedNames list of child names that is currently used and may not be chosen. - * @param string[] $namespaces namespace prefix to uri map of all currently known namespaces. - * @param string $defaultNamespace namespace prefix to use if the hint does not specify. - * @param string $nameHint the name hint according to the API definition + * @param string[] $usedNames list of child names that is currently used and may not be chosen + * @param string[] $namespaces namespace prefix to uri map of all currently known namespaces + * @param string $defaultNamespace namespace prefix to use if the hint does not specify + * @param string|null $nameHint the name hint according to the API definition * + * @return string A valid node name for this node + * @return string A valid node name for this node + * + * @throws RepositoryException * @throws NamespaceException if a namespace prefix is provided in the * $nameHint which does not exist and this implementation performs - * this validation immediately. - * @throws RepositoryException - * - * @return string A valid node name for this node + * this validation immediately */ - public static function generateAutoNodeName($usedNames, $namespaces, $defaultNamespace, $nameHint = null) + public static function generateAutoNodeName(array $usedNames, array $namespaces, string $defaultNamespace, ?string $nameHint = null): string { $usedNames = array_flip($usedNames); @@ -179,7 +162,7 @@ public static function generateAutoNodeName($usedNames, $namespaces, $defaultNam * valid namespace prefix */ if (':' === $nameHint[strlen($nameHint) - 1] - && substr_count($nameHint, ':') === 1 + && 1 === substr_count($nameHint, ':') && preg_match('#^[a-zA-Z][a-zA-Z0-9]*:$#', $nameHint) ) { $prefix = substr($nameHint, 0, -1); @@ -217,7 +200,7 @@ public static function generateAutoNodeName($usedNames, $namespaces, $defaultNam * constructed from the hint may vary across implementations. */ if (1 === substr_count($nameHint, ':')) { - list($prefix, $name) = explode(':', $nameHint); + [$prefix, $name] = explode(':', $nameHint); if (preg_match('#^[a-zA-Z][a-zA-Z0-9]*$#', $prefix) && preg_match('#^[a-zA-Z][a-zA-Z0-9]*$#', $name) ) { @@ -243,7 +226,7 @@ public static function generateAutoNodeName($usedNames, $namespaces, $defaultNam $ns = $matches[1]; $name = $matches[2]; - $prefix = array_search($ns, $namespaces); + $prefix = array_search($ns, $namespaces, true); if (!$prefix) { throw new NamespaceException("Invalid nameHint '$nameHint'"); } @@ -261,10 +244,8 @@ public static function generateAutoNodeName($usedNames, $namespaces, $defaultNam * @param string[] $usedNames names that are forbidden * @param string $prefix the prefix including the colon at the end * @param string $namepart start for the localname - * - * @return string */ - private static function generateWithPrefix($usedNames, $prefix, $namepart = '') + private static function generateWithPrefix(array $usedNames, string $prefix, string $namepart = ''): string { do { $name = $prefix.$namepart.mt_rand(); @@ -288,17 +269,17 @@ private static function generateWithPrefix($usedNames, $prefix, $namepart = '') * @param array $new new order * * @return array the keys are elements to move, values the destination to - * move before or null to move to the end. + * move before or null to move to the end */ - public static function calculateOrderBefore(array $old, array $new) + public static function calculateOrderBefore(array $old, array $new): array { $reorders = []; - //check for deleted items + // check for deleted items $newIndex = array_flip($new); foreach ($old as $key => $value) { - if (!isset($newIndex[$value])) { + if (!array_key_exists($value, $newIndex)) { unset($old[$key]); } } @@ -310,23 +291,23 @@ public static function calculateOrderBefore(array $old, array $new) $len = count($new) - 1; $oldIndex = array_flip($old); - //go backwards on the new node order and arrange them this way - for ($i = $len; $i >= 0; $i--) { - //get the name of the child node + // go backwards on the new node order and arrange them this way + for ($i = $len; $i >= 0; --$i) { + // get the name of the child node $current = $new[$i]; - //check if it's not the last node + // check if it's not the last node if (isset($new[$i + 1])) { // get the name of the next node $next = $new[$i + 1]; - //if in the old order $c and next are not neighbors already, do the reorder command - if ($oldIndex[$current] + 1 != $oldIndex[$next]) { + // if in the old order $c and next are not neighbors already, do the reorder command + if ($oldIndex[$current] + 1 !== $oldIndex[$next]) { $reorders[$current] = $next; $old = self::orderBeforeArray($current, $next, $old); $oldIndex = array_flip($old); } } else { - //check if it's not already at the end of the nodes - if ($oldIndex[$current] != $len) { + // check if it's not already at the end of the nodes + if ($oldIndex[$current] !== $len) { $reorders[$current] = null; $old = self::orderBeforeArray($current, null, $old); $oldIndex = array_flip($old); @@ -341,38 +322,38 @@ public static function calculateOrderBefore(array $old, array $new) * Move the element $name of $list to right before $destination, * validating existence of all elements. * - * @param string $name name of the element to move - * @param string $destination name of the element $srcChildRelPath has - * to be ordered before, null to move to the end - * @param array $list the array of names - * - * @throws ItemNotFoundException if $srcChildRelPath or $destChildRelPath are not found in $nodes + * @param string $name name of the element to move + * @param string|null $destination name of the element $srcChildRelPath has + * to be ordered before, null to move to the end + * @param array $list the array of names * * @return array The updated $nodes array with new order + * + * @throws ItemNotFoundException if $srcChildRelPath or $destChildRelPath are not found in $nodes */ - public static function orderBeforeArray($name, $destination, $list) + public static function orderBeforeArray(string $name, ?string $destination, array $list): array { // reindex the array so there are no gaps $list = array_values($list); - $oldpos = array_search($name, $list); + $oldpos = array_search($name, $list, true); if (false === $oldpos) { throw new ItemNotFoundException("$name is not a child of this node"); } - if ($destination == null) { + if (null === $destination) { // null means move to end unset($list[$oldpos]); $list[] = $name; } else { // insert before element $destination - $newpos = array_search($destination, $list); - if ($newpos === false) { + $newpos = array_search($destination, $list, true); + if (false === $newpos) { throw new ItemNotFoundException("$destination is not a child of this node"); } if ($oldpos < $newpos) { // we first unset, the position will change by one - $newpos--; + --$newpos; } unset($list[$oldpos]); array_splice($list, $newpos, 0, $name); diff --git a/src/PHPCR/Util/PathHelper.php b/src/PHPCR/Util/PathHelper.php index 8fba4160..ffa1464f 100644 --- a/src/PHPCR/Util/PathHelper.php +++ b/src/PHPCR/Util/PathHelper.php @@ -1,5 +1,7 @@ 1 && '/' === $path[strlen($path) - 1] || preg_match('-//|/\./|/\.\./-', $path) + || (strlen($path) > 1 && '/' === $path[strlen($path) - 1]) ) { return self::error("Invalid path '$path'", $throw); } @@ -85,15 +86,15 @@ public static function assertValidAbsolutePath($path, $destination = false, $thr * engine. * * @param string $name The name to check - * @param bool $throw whether to throw an exception on validation errors. - * - * @throws RepositoryException if the name is invalid and $throw is true + * @param bool $throw whether to throw an exception on validation errors * * @return bool true if valid, false if not valid and $throw was false * + * @throws RepositoryException if the name is invalid and $throw is true + * * @see http://www.day.com/specs/jcr/2.0/3_Repository_Model.html#3.2.2%20Local%20Names */ - public static function assertValidLocalName($name, $throw = true) + public static function assertValidLocalName(string $name, bool $throw = true): bool { if ('.' === $name || '..' === $name) { return self::error("Name may not be parent or self identifier: $name", $throw); @@ -117,23 +118,20 @@ public static function assertValidLocalName($name, $throw = true) * * Note: A well-formed input path implies a well-formed and normalized path returned. * - * @param string $path The path to normalize. + * @param string $path the path to normalize * @param bool $destination whether this is a destination path (by copy or - * move), meaning [] is not allowed in validation. + * move), meaning [] is not allowed in validation * @param bool $throw whether to throw an exception if validation fails or - * just to return false. + * just to return false + * + * @return false|string The normalized path or false if $throw was false and the path invalid * * @throws RepositoryException if the path is not a valid absolute path and * $throw is true - * - * @return string The normalized path or false if $throw was false and the path invalid */ - public static function normalizePath($path, $destination = false, $throw = true) + public static function normalizePath(string $path, bool $destination = false, bool $throw = true): false|string { - if (!is_string($path) && !is_numeric($path)) { - return self::error('Expected string but got '.gettype($path), $throw); - } - if (strlen($path) === 0) { + if ('' === $path) { return self::error('Path must not be of zero length', $throw); } @@ -181,25 +179,19 @@ public static function normalizePath($path, $destination = false, $throw = true) * @param string $path A relative or absolute path * @param string $context The absolute path context to make $path absolute if needed * @param bool $destination whether this is a destination path (by copy or - * move), meaning [] is not allowed in validation. + * move), meaning [] is not allowed in validation * @param bool $throw whether to throw an exception if validation fails or - * just to return false. + * just to return false + * + * @return false|string The normalized, absolute path or false if $throw was + * false and the path invalid * * @throws RepositoryException if the path can not be made into a valid * absolute path and $throw is true - * - * @return string The normalized, absolute path or false if $throw was - * false and the path invalid */ - public static function absolutizePath($path, $context, $destination = false, $throw = true) + public static function absolutizePath(string $path, string $context, bool $destination = false, bool $throw = true): false|string { - if (!is_string($path) && !is_numeric($path)) { - return self::error('Expected string path but got '.gettype($path), $throw); - } - if (!is_string($context)) { - return self::error('Expected string context but got '.gettype($context), $throw); - } - if (strlen($path) === 0) { + if ('' === $path) { return self::error('Path must not be of zero length', $throw); } @@ -219,13 +211,13 @@ public static function absolutizePath($path, $context, $destination = false, $th * * @param string $path The absolute path to a node * @param string $context The absolute path to an ancestor of $path - * @param bool $throw Whether to throw exceptions on invalid data. + * @param bool $throw whether to throw exceptions on invalid data * - * @return string The relative path from $context to $path + * @return false|string The relative path from $context to $path */ - public static function relativizePath($path, $context, $throw = true) + public static function relativizePath(string $path, string $context, bool $throw = true): false|string { - if ($context !== substr($path, 0, strlen($context))) { + if (!str_starts_with($path, $context)) { return self::error("$path is not within $context", $throw); } @@ -239,7 +231,7 @@ public static function relativizePath($path, $context, $throw = true) * * @return string the path with the last segment removed */ - public static function getParentPath($path) + public static function getParentPath(string $path): string { if ('/' === $path) { return '/'; @@ -261,11 +253,11 @@ public static function getParentPath($path) * * @param string $path a valid absolute path, like /content/jobs/data * - * @throws RepositoryException - * * @return string the name, that is the string after the last "/" + * + * @throws RepositoryException */ - public static function getNodeName($path) + public static function getNodeName(string $path): string { $strrpos = strrpos($path, '/'); @@ -286,10 +278,8 @@ public static function getNodeName($path) * @param string $path a valid absolute path * * @throws RepositoryException - * - * @return string The localname */ - public static function getLocalNodeName($path) + public static function getLocalNodeName(string $path): string { $nodeName = self::getNodeName($path); $localName = strstr($nodeName, ':'); @@ -308,7 +298,7 @@ public static function getLocalNodeName($path) * * @return int with the path depth */ - public static function getPathDepth($path) + public static function getPathDepth(string $path): int { return substr_count(rtrim($path, '/'), '/'); } @@ -320,11 +310,11 @@ public static function getPathDepth($path) * @param string $msg the exception message to use in case of throw being true * @param bool $throw whether to throw the exception or return false * - * @throws RepositoryException + * @return false * - * @return bool false + * @throws RepositoryException */ - private static function error($msg, $throw) + private static function error(string $msg, bool $throw): bool { if ($throw) { throw new RepositoryException($msg); diff --git a/src/PHPCR/Util/QOM/BaseQomToSqlQueryConverter.php b/src/PHPCR/Util/QOM/BaseQomToSqlQueryConverter.php index b9f2801e..928ac90f 100644 --- a/src/PHPCR/Util/QOM/BaseQomToSqlQueryConverter.php +++ b/src/PHPCR/Util/QOM/BaseQomToSqlQueryConverter.php @@ -1,8 +1,9 @@ generator = $generator; @@ -36,19 +27,15 @@ public function __construct(BaseSqlGenerator $generator) * 'FROM' Source * ['WHERE' Constraint] * ['ORDER BY' orderings]. - * - * @param QOM\QueryObjectModelInterface $query - * - * @return string */ - public function convert(QOM\QueryObjectModelInterface $query) + public function convert(QOM\QueryObjectModelInterface $query): string { $columns = $this->convertColumns($query->getColumns()); $source = $this->convertSource($query->getSource()); $constraint = ''; $orderings = ''; - if ($query->getConstraint() !== null) { + if (null !== $query->getConstraint()) { $constraint = $this->convertConstraint($query->getConstraint()); } @@ -61,40 +48,24 @@ public function convert(QOM\QueryObjectModelInterface $query) /** * Convert a source. This is different between SQL1 and SQL2. - * - * @param QOM\SourceInterface $source - * - * @return string */ - abstract protected function convertSource(QOM\SourceInterface $source); + abstract protected function convertSource(QOM\SourceInterface $source): string; /** * Convert a constraint. This is different between SQL1 and SQL2. - * - * @param QOM\ConstraintInterface $constraint - * - * @return string */ - abstract protected function convertConstraint(QOM\ConstraintInterface $constraint); + abstract protected function convertConstraint(QOM\ConstraintInterface $constraint): string; /** * Convert dynamic operand. This is different between SQL1 and SQL2. - * - * @param QOM\DynamicOperandInterface $operand - * - * @return mixed */ - abstract protected function convertDynamicOperand(QOM\DynamicOperandInterface $operand); + abstract protected function convertDynamicOperand(QOM\DynamicOperandInterface $operand): mixed; /** * Selector ::= nodeTypeName ['AS' selectorName] * nodeTypeName ::= Name. - * - * @param QOM\SelectorInterface $selector - * - * @return string */ - protected function convertSelector(QOM\SelectorInterface $selector) + protected function convertSelector(QOM\SelectorInterface $selector): string { return $this->generator->evalSelector($selector->getNodeTypeName(), $selector->getSelectorName()); } @@ -112,12 +83,8 @@ protected function convertSelector(QOM\SelectorInterface $selector) * GreaterThan ::= '>' * GreaterThanOrEqualTo ::= '>=' * Like ::= 'LIKE' - * - * @param QOM\ComparisonInterface $comparison - * - * @return string */ - protected function convertComparison(QOM\ComparisonInterface $comparison) + protected function convertComparison(QOM\ComparisonInterface $comparison): string { $operand1 = $this->convertDynamicOperand($comparison->getOperand1()); $operand2 = $this->convertStaticOperand($comparison->getOperand2()); @@ -135,12 +102,8 @@ protected function convertComparison(QOM\ComparisonInterface $comparison) * * Note: The negation, 'NOT x IS NOT NULL' * can be written 'x IS NULL' - * - * @param QOM\PropertyExistenceInterface $constraint - * - * @return string */ - protected function convertPropertyExistence(QOM\PropertyExistenceInterface $constraint) + protected function convertPropertyExistence(QOM\PropertyExistenceInterface $constraint): string { return $this->generator->evalPropertyExistence( $constraint->getSelectorName(), @@ -156,12 +119,8 @@ protected function convertPropertyExistence(QOM\PropertyExistenceInterface $cons * // If only one selector exists in this query, * explicit specification of the selectorName * preceding the propertyName is optional. - * - * @param QOM\FullTextSearchInterface $constraint - * - * @return string */ - protected function convertFullTextSearch(QOM\FullTextSearchInterface $constraint) + protected function convertFullTextSearch(QOM\FullTextSearchInterface $constraint): string { $searchExpression = $this->convertFullTextSearchExpression($constraint->getFullTextSearchExpression()); @@ -171,11 +130,9 @@ protected function convertFullTextSearch(QOM\FullTextSearchInterface $constraint /** * FullTextSearchExpression ::= BindVariable | ''' FullTextSearchLiteral '''. * - * @param string|QOM\StaticOperandInterface $expr - * - * @return string + * @param string|StaticOperandInterface $expr */ - protected function convertFullTextSearchExpression($expr) + protected function convertFullTextSearchExpression($expr): string { if ($expr instanceof QOM\BindVariableValueInterface) { return $this->convertBindVariable($expr->getBindVariableName()); @@ -187,7 +144,7 @@ protected function convertFullTextSearchExpression($expr) // however, without type checks, jackalope 1.0 got this wrong and returned a string. $literal = $expr; } else { - throw new InvalidArgumentException('Unknown full text search expression type '.get_class($expr)); + throw new \InvalidArgumentException('Unknown full text search expression type '.$expr::class); } $literal = $this->generator->evalFullText($literal); @@ -210,13 +167,9 @@ protected function convertFullTextSearchExpression($expr) * BindVariableValue ::= '$'bindVariableName * bindVariableName ::= Prefix * - * @param QOM\StaticOperandInterface $operand - * - * @throws InvalidArgumentException - * - * @return string + * @throws \InvalidArgumentException */ - protected function convertStaticOperand(QOM\StaticOperandInterface $operand) + protected function convertStaticOperand(StaticOperandInterface $operand): string { if ($operand instanceof QOM\BindVariableValueInterface) { return $this->convertBindVariable($operand->getBindVariableName()); @@ -226,17 +179,13 @@ protected function convertStaticOperand(QOM\StaticOperandInterface $operand) } // This should not happen, but who knows... - throw new InvalidArgumentException('Invalid operand'); + throw new \InvalidArgumentException('Invalid operand'); } /** * PropertyValue ::= [selectorName'.'] propertyName // If only one selector exists. - * - * @param QOM\PropertyValueInterface $value - * - * @return string */ - protected function convertPropertyValue(QOM\PropertyValueInterface $value) + protected function convertPropertyValue(QOM\PropertyValueInterface $value): string { return $this->generator->evalPropertyValue( $value->getPropertyName(), @@ -252,10 +201,8 @@ protected function convertPropertyValue(QOM\PropertyValueInterface $value) * Descending ::= 'DESC'. * * @param QOM\OrderingInterface[] $orderings - * - * @return string */ - protected function convertOrderings(array $orderings) + protected function convertOrderings(array $orderings): string { $list = []; foreach ($orderings as $ordering) { @@ -271,12 +218,8 @@ protected function convertOrderings(array $orderings) * Path ::= '[' quotedPath ']' | '[' simplePath ']' | simplePath * quotedPath ::= A JCR Path that contains non-SQL-legal characters * simplePath ::= A JCR Name that contains only SQL-legal characters. - * - * @param string $path - * - * @return string */ - protected function convertPath($path) + protected function convertPath(string $path): string { return $this->generator->evalPath($path); } @@ -284,24 +227,16 @@ protected function convertPath($path) /** * BindVariableValue ::= '$'bindVariableName * bindVariableName ::= Prefix. - * - * @param string $var - * - * @return string */ - protected function convertBindVariable($var) + protected function convertBindVariable(string $var): string { return $this->generator->evalBindVariable($var); } /** * Literal ::= CastLiteral | UncastLiteral. - * - * @param mixed $literal - * - * @return string */ - protected function convertLiteral($literal) + protected function convertLiteral(mixed $literal): string { return $this->generator->evalLiteral($literal); } @@ -316,10 +251,8 @@ protected function convertLiteral($literal) * columnName ::= Name. * * @param QOM\ColumnInterface[] $columns - * - * @return string */ - protected function convertColumns(array $columns) + protected function convertColumns(array $columns): string { $list = []; diff --git a/src/PHPCR/Util/QOM/BaseSqlGenerator.php b/src/PHPCR/Util/QOM/BaseSqlGenerator.php index e023fbdc..365d625f 100644 --- a/src/PHPCR/Util/QOM/BaseSqlGenerator.php +++ b/src/PHPCR/Util/QOM/BaseSqlGenerator.php @@ -1,8 +1,9 @@ 'ASC', + Constants::JCR_ORDER_DESCENDING => 'DESC', + default => '', + }; } /** * BindVariableValue ::= '$'bindVariableName * bindVariableName ::= Prefix. - * - * @param $var - * - * @return string */ - public function evalBindVariable($var) + public function evalBindVariable(string $var): string { return '$'.$var; } @@ -232,17 +173,15 @@ public function evalBindVariable($var) /** * Escape the illegal characters for inclusion in a fulltext statement. Escape Character is \\. * - * @param string $string - * * @return string Escaped String * * @see http://jackrabbit.apache.org/api/1.4/org/apache/jackrabbit/util/Text.html #escapeIllegalJcrChars */ - public function evalFullText($string) + public function evalFullText(string $string): string { $illegalCharacters = [ - '!' => '\\!', '(' => '\\(', ':' => '\\:', '^' => '\\^', - '[' => '\\[', ']' => '\\]', '{' => '\\{', '}' => '\\}', + '!' => '\\!', '(' => '\\(', ':' => '\\:', '^' => '\\^', + '[' => '\\[', ']' => '\\]', '{' => '\\{', '}' => '\\}', '\"' => '\\\"', '?' => '\\?', "'" => "''", ]; @@ -251,14 +190,10 @@ public function evalFullText($string) /** * Literal ::= CastLiteral | UncastLiteral. - * - * @param mixed $literal - * - * @return string */ - public function evalLiteral($literal) + public function evalLiteral(mixed $literal): string { - if ($literal instanceof DateTime) { + if ($literal instanceof \DateTime) { $string = $this->valueConverter->convertType($literal, PropertyType::STRING); return $this->evalCastLiteral($string, 'DATE'); @@ -279,96 +214,45 @@ public function evalLiteral($literal) return $this->evalCastLiteral($string, 'DOUBLE'); } - return "'$literal'"; + return sprintf("'%s'", str_replace("'", "''", $literal)); } /** * Cast a literal. This is different between SQL1 and SQL2. - * - * @param string $literal - * @param string $type - * - * @return string */ - abstract public function evalCastLiteral($literal, $type); + abstract public function evalCastLiteral(string $literal, string $type): string; /** * @param string $nodeTypeName The node type of the selector. If it does not contain starting and ending * brackets ([]), they will be added automatically. * @param string|null $selectorName The selector name. If it is different than the nodeTypeName, the alias is * declared if supported by the SQL dialect. - * - * @return string */ - abstract public function evalSelector($nodeTypeName, $selectorName = null); + abstract public function evalSelector(string $nodeTypeName, ?string $selectorName = null): string; /** * Evaluate a path. This is different between SQL1 and SQL2. - * - * @param string $path - * - * @return string|null */ - abstract public function evalPath($path); + abstract public function evalPath(string $path): string; /** * columns ::= (Column ',' {Column}) | '*'. * * With empty columns, SQL1 is different from SQL2 * - * @param $columns - * - * @return string + * @param iterable $columns */ - abstract public function evalColumns($columns); + abstract public function evalColumns(iterable $columns): string; - /** - * @param string $selectorName - * @param string $propertyName - * @param string $colname - * - * @return string - */ - abstract public function evalColumn($selectorName, $propertyName = null, $colname = null); + abstract public function evalColumn(string $selectorName, ?string $propertyName = null, ?string $colname = null): string; - /** - * @param $selectorName - * @param $propertyName - * - * @return string - */ - abstract public function evalPropertyExistence($selectorName, $propertyName); + abstract public function evalPropertyExistence(?string $selectorName, string $propertyName): string; - /** - * @param string $propertyName - * @param string $selectorName - * - * @return string - */ - abstract public function evalPropertyValue($propertyName, $selectorName = null); + abstract public function evalPropertyValue(string $propertyName, ?string $selectorName = null); - /** - * @param string $path - * @param string $selectorName - * - * @return string - */ - abstract public function evalChildNode($path, $selectorName = null); + abstract public function evalChildNode(string $path, ?string $selectorName = null); - /** - * @param string $path - * @param string $selectorName - * - * @return string - */ - abstract public function evalDescendantNode($path, $selectorName = null); + abstract public function evalDescendantNode(string $path, ?string $selectorName = null): string; - /** - * @param string $selectorName - * @param string $searchExpression - * @param string $propertyName - * - * @return string - */ - abstract public function evalFullTextSearch($selectorName, $searchExpression, $propertyName = null); + abstract public function evalFullTextSearch(string $selectorName, string $searchExpression, ?string $propertyName = null): string; } diff --git a/src/PHPCR/Util/QOM/NotSupportedConstraintException.php b/src/PHPCR/Util/QOM/NotSupportedConstraintException.php index 223e8507..4c245dec 100644 --- a/src/PHPCR/Util/QOM/NotSupportedConstraintException.php +++ b/src/PHPCR/Util/QOM/NotSupportedConstraintException.php @@ -1,8 +1,8 @@ convertSelector($source); } - throw new InvalidArgumentException('Invalid Source'); + throw new \InvalidArgumentException('Invalid Source'); } /** @@ -40,14 +37,10 @@ protected function convertSource(QOM\SourceInterface $source) * Or ::= constraint1 'OR' constraint2 * Not ::= 'NOT' Constraint * - * @param QOM\ConstraintInterface $constraint - * - * @throws InvalidArgumentException + * @throws \InvalidArgumentException * @throws NotSupportedConstraintException - * - * @return string */ - protected function convertConstraint(QOM\ConstraintInterface $constraint) + protected function convertConstraint(QOM\ConstraintInterface $constraint): string { if ($constraint instanceof QOM\AndInterface) { return $this->generator->evalAnd( @@ -73,12 +66,13 @@ protected function convertConstraint(QOM\ConstraintInterface $constraint) if ($constraint instanceof QOM\PropertyExistenceInterface) { return $this->convertPropertyExistence($constraint); - } elseif ($constraint instanceof QOM\FullTextSearchInterface) { + } + if ($constraint instanceof QOM\FullTextSearchInterface) { return $this->convertFullTextSearch($constraint); } if ($constraint instanceof QOM\SameNodeInterface) { - throw new NotSupportedConstraintException($constraint); + throw NotSupportedConstraintException::fromConstraint($constraint); } if ($constraint instanceof QOM\ChildNodeInterface) { @@ -94,9 +88,9 @@ protected function convertConstraint(QOM\ConstraintInterface $constraint) } // This should not happen, but who knows... - $class = get_class($constraint); + $class = $constraint::class; - throw new InvalidArgumentException("Invalid operand: $class"); + throw new \InvalidArgumentException("Invalid operand: $class"); } /** @@ -105,48 +99,44 @@ protected function convertConstraint(QOM\ConstraintInterface $constraint) * LowerCase ::= 'LOWER(' DynamicOperand ')' * UpperCase ::= 'UPPER(' DynamicOperand ')' * - * @param QOM\DynamicOperandInterface $operand - * * @throws NotSupportedOperandException - * @throws InvalidArgumentException - * - * @return string + * @throws \InvalidArgumentException */ - protected function convertDynamicOperand(QOM\DynamicOperandInterface $operand) + protected function convertDynamicOperand(QOM\DynamicOperandInterface $operand): string { if ($operand instanceof QOM\PropertyValueInterface) { return $this->convertPropertyValue($operand); } if ($operand instanceof QOM\LengthInterface) { - throw new NotSupportedOperandException($operand); + throw NotSupportedOperandException::fromOperand($operand); } if ($operand instanceof QOM\NodeNameInterface) { - throw new NotSupportedOperandException($operand); + throw NotSupportedOperandException::fromOperand($operand); } if ($operand instanceof QOM\NodeLocalNameInterface) { - throw new NotSupportedOperandException($operand); + throw NotSupportedOperandException::fromOperand($operand); } if ($operand instanceof QOM\FullTextSearchScoreInterface) { - throw new NotSupportedOperandException($operand); + throw NotSupportedOperandException::fromOperand($operand); } if ($operand instanceof QOM\LowerCaseInterface) { - $operand = $this->convertDynamicOperand($operand->getOperand()); + $operandText = $this->convertDynamicOperand($operand->getOperand()); - return $this->generator->evalLower($operand); + return $this->generator->evalLower($operandText); } if ($operand instanceof QOM\UpperCaseInterface) { - $operand = $this->convertDynamicOperand($operand->getOperand()); + $operandText = $this->convertDynamicOperand($operand->getOperand()); - return $this->generator->evalUpper($operand); + return $this->generator->evalUpper($operandText); } // This should not happen, but who knows... - throw new InvalidArgumentException('Invalid operand'); + throw new \InvalidArgumentException('Invalid operand'); } } diff --git a/src/PHPCR/Util/QOM/QomToSql2QueryConverter.php b/src/PHPCR/Util/QOM/QomToSql2QueryConverter.php index fdef9c07..5a364449 100644 --- a/src/PHPCR/Util/QOM/QomToSql2QueryConverter.php +++ b/src/PHPCR/Util/QOM/QomToSql2QueryConverter.php @@ -1,8 +1,9 @@ convertSelector($source); @@ -31,7 +28,7 @@ protected function convertSource(QOM\SourceInterface $source) return $this->convertJoin($source); } - throw new InvalidArgumentException('Invalid Source'); + throw new \InvalidArgumentException('Invalid Source'); } /** @@ -44,12 +41,8 @@ protected function convertSource(QOM\SourceInterface $source) * Inner ::= 'INNER' * LeftOuter ::= 'LEFT OUTER' * RightOuter ::= 'RIGHT OUTER' - * - * @param QOM\JoinInterface $join - * - * @return string */ - protected function convertJoin(QOM\JoinInterface $join) + protected function convertJoin(QOM\JoinInterface $join): string { if (!$this->generator instanceof Sql2Generator) { throw new NotSupportedOperandException('Only SQL2 supports join'); @@ -68,13 +61,9 @@ protected function convertJoin(QOM\JoinInterface $join) * ChildNodeJoinCondition | * DescendantNodeJoinCondition. * - * @param QOM\JoinConditionInterface $condition - * - * @throws InvalidArgumentException - * - * @return string + * @throws \InvalidArgumentException */ - protected function convertJoinCondition(QOM\JoinConditionInterface $condition) + protected function convertJoinCondition(QOM\JoinConditionInterface $condition): string { if ($condition instanceof QOM\EquiJoinConditionInterface) { return $this->convertEquiJoinCondition($condition); @@ -90,7 +79,7 @@ protected function convertJoinCondition(QOM\JoinConditionInterface $condition) } // This should not happen, but who knows... - throw new InvalidArgumentException('Invalid operand'); + throw new \InvalidArgumentException('Invalid operand'); } /** @@ -100,12 +89,8 @@ protected function convertJoinCondition(QOM\JoinConditionInterface $condition) * selector2Name ::= selectorName * property1Name ::= propertyName * property2Name ::= propertyName. - * - * @param QOM\EquiJoinConditionInterface $condition - * - * @return string */ - protected function convertEquiJoinCondition(QOM\EquiJoinConditionInterface $condition) + protected function convertEquiJoinCondition(QOM\EquiJoinConditionInterface $condition): string { if (!$this->generator instanceof Sql2Generator) { throw new NotSupportedOperandException('Only SQL2 supports equi join condition'); @@ -125,12 +110,8 @@ protected function convertEquiJoinCondition(QOM\EquiJoinConditionInterface $cond * selector2Name * [',' selector2Path] ')' * selector2Path ::= Path. - * - * @param QOM\SameNodeJoinConditionInterface $condition - * - * @return string */ - protected function convertSameNodeJoinCondition(QOM\SameNodeJoinConditionInterface $condition) + protected function convertSameNodeJoinCondition(QOM\SameNodeJoinConditionInterface $condition): string { if (!$this->generator instanceof Sql2Generator) { throw new NotSupportedOperandException('Only SQL2 supports same node join condition'); @@ -149,12 +130,8 @@ protected function convertSameNodeJoinCondition(QOM\SameNodeJoinConditionInterfa * parentSelectorName ')' * childSelectorName ::= selectorName * parentSelectorName ::= selectorName. - * - * @param QOM\ChildNodeJoinConditionInterface $condition - * - * @return string */ - protected function convertChildNodeJoinCondition(QOM\ChildNodeJoinConditionInterface $condition) + protected function convertChildNodeJoinCondition(QOM\ChildNodeJoinConditionInterface $condition): string { if (!$this->generator instanceof Sql2Generator) { throw new NotSupportedOperandException('Only SQL2 supports child node join condition'); @@ -172,12 +149,8 @@ protected function convertChildNodeJoinCondition(QOM\ChildNodeJoinConditionInter * ancestorSelectorName ')' * descendantSelectorName ::= selectorName * ancestorSelectorName ::= selectorName. - * - * @param QOM\DescendantNodeJoinConditionInterface $condition - * - * @return string */ - protected function convertDescendantNodeJoinCondition(QOM\DescendantNodeJoinConditionInterface $condition) + protected function convertDescendantNodeJoinCondition(QOM\DescendantNodeJoinConditionInterface $condition): string { if (!$this->generator instanceof Sql2Generator) { throw new NotSupportedOperandException('Only SQL2 supports descendant node join condition'); @@ -210,13 +183,9 @@ protected function convertDescendantNodeJoinCondition(QOM\DescendantNodeJoinCond * // If only one selector exists in this query, explicit * specification of the selectorName is optional * - * @param QOM\ConstraintInterface $constraint - * - * @throws InvalidArgumentException - * - * @return string + * @throws \InvalidArgumentException */ - protected function convertConstraint(QOM\ConstraintInterface $constraint) + protected function convertConstraint(QOM\ConstraintInterface $constraint): string { if ($constraint instanceof QOM\AndInterface) { return $this->generator->evalAnd( @@ -273,7 +242,7 @@ protected function convertConstraint(QOM\ConstraintInterface $constraint) } // This should not happen, but who knows... - throw new InvalidArgumentException('Invalid operand: '.get_class($constraint)); + throw new \InvalidArgumentException('Invalid operand: '.$constraint::class); } /** @@ -288,13 +257,9 @@ protected function convertConstraint(QOM\ConstraintInterface $constraint) * LowerCase ::= 'LOWER(' DynamicOperand ')' * UpperCase ::= 'UPPER(' DynamicOperand ')' * - * @param QOM\DynamicOperandInterface $operand - * - * @throws InvalidArgumentException - * - * @return string + * @throws \InvalidArgumentException */ - protected function convertDynamicOperand(QOM\DynamicOperandInterface $operand) + protected function convertDynamicOperand(QOM\DynamicOperandInterface $operand): string { if ($operand instanceof QOM\PropertyValueInterface) { return $this->convertPropertyValue($operand); @@ -345,6 +310,6 @@ protected function convertDynamicOperand(QOM\DynamicOperandInterface $operand) } // This should not happen, but who knows... - throw new InvalidArgumentException('Invalid operand'); + throw new \InvalidArgumentException('Invalid operand'); } } diff --git a/src/PHPCR/Util/QOM/QueryBuilder.php b/src/PHPCR/Util/QOM/QueryBuilder.php index 23c6c125..046bc872 100644 --- a/src/PHPCR/Util/QOM/QueryBuilder.php +++ b/src/PHPCR/Util/QOM/QueryBuilder.php @@ -1,8 +1,9 @@ the query parameters */ - private $query = null; + private array $params = []; - /** - * @var array The query parameters. - */ - private $params = []; - - /** - * Initializes a new QueryBuilder. - * - * @param QueryObjectModelFactoryInterface $qomFactory - */ - public function __construct(QueryObjectModelFactoryInterface $qomFactory) - { - $this->qomFactory = $qomFactory; + public function __construct( + private QueryObjectModelFactoryInterface $qomFactory + ) { } /** * Get a query builder instance from an existing query. * - * @param string $statement the statement in the specified language - * @param string $language the query language + * @param string|QueryObjectModelInterface $statement the statement in the specified language * - * @throws InvalidArgumentException - * - * @return QueryBuilder This QueryBuilder instance. + * @throws \InvalidArgumentException */ - public function setFromQuery($statement, $language) + public function setFromQuery(string|QueryObjectModelInterface $statement, string $queryLanguage): static { - if (QueryInterface::JCR_SQL2 === $language) { + if (QueryInterface::JCR_SQL2 === $queryLanguage) { $converter = new Sql2ToQomQueryConverter($this->qomFactory); $statement = $converter->parse($statement); } if (!$statement instanceof QueryObjectModelInterface) { - throw new InvalidArgumentException("Language '$language' not supported"); + throw new \InvalidArgumentException("Language '$queryLanguage' not supported"); } $this->state = self::STATE_DIRTY; @@ -123,12 +99,7 @@ public function setFromQuery($statement, $language) return $this; } - /** - * Get the associated QOMFactory for this query builder. - * - * @return QueryObjectModelFactoryInterface - */ - public function getQOMFactory() + public function getQOMFactory(): QueryObjectModelFactoryInterface { return $this->qomFactory; } @@ -136,19 +107,15 @@ public function getQOMFactory() /** * Shortcut for getQOMFactory(). */ - public function qomf() + public function qomf(): QueryObjectModelFactoryInterface { return $this->getQOMFactory(); } /** * sets the position of the first result to retrieve (the "offset"). - * - * @param int $firstResult The First result to return. - * - * @return QueryBuilder This QueryBuilder instance. */ - public function setFirstResult($firstResult) + public function setFirstResult(int $firstResult): static { $this->firstResult = $firstResult; @@ -159,21 +126,17 @@ public function setFirstResult($firstResult) * Gets the position of the first result the query object was set to retrieve (the "offset"). * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder. * - * @return int The position of the first result. + * @return int the position of the first result */ - public function getFirstResult() + public function getFirstResult(): int { return $this->firstResult; } /** * Sets the maximum number of results to retrieve (the "limit"). - * - * @param int $maxResults The maximum number of results to retrieve. - * - * @return QueryBuilder This QueryBuilder instance. */ - public function setMaxResults($maxResults) + public function setMaxResults(int $maxResults): static { $this->maxResults = $maxResults; @@ -183,20 +146,16 @@ public function setMaxResults($maxResults) /** * Gets the maximum number of results the query object was set to retrieve (the "limit"). * Returns NULL if {@link setMaxResults} was not applied to this query builder. - * - * @return int Maximum number of results. */ - public function getMaxResults() + public function getMaxResults(): int { return $this->maxResults; } /** - * Gets the array of orderings. - * - * @return OrderingInterface[] Orderings to apply. + * @return OrderingInterface[] */ - public function getOrderings() + public function getOrderings(): array { return $this->orderings; } @@ -204,23 +163,21 @@ public function getOrderings() /** * Adds an ordering to the query results. * - * @param DynamicOperandInterface $sort The ordering expression. - * @param string $order The ordering direction. + * @param DynamicOperandInterface $sort the ordering expression + * @param string $order the ordering direction * - * @throws InvalidArgumentException - * - * @return QueryBuilder This QueryBuilder instance. + * @throws \InvalidArgumentException */ - public function addOrderBy(DynamicOperandInterface $sort, $order = 'ASC') + public function addOrderBy(DynamicOperandInterface $sort, string $order = 'ASC'): static { $order = strtoupper($order); if (!in_array($order, ['ASC', 'DESC'])) { - throw new InvalidArgumentException('Order must be one of "ASC" or "DESC"'); + throw new \InvalidArgumentException('Order must be one of "ASC" or "DESC"'); } $this->state = self::STATE_DIRTY; - if ($order === 'DESC') { + if ('DESC' === $order) { $ordering = $this->qomFactory->descending($sort); } else { $ordering = $this->qomFactory->ascending($sort); @@ -234,12 +191,10 @@ public function addOrderBy(DynamicOperandInterface $sort, $order = 'ASC') * Specifies an ordering for the query results. * Replaces any previously specified orderings, if any. * - * @param DynamicOperandInterface $sort The ordering expression. - * @param string $order The ordering direction. - * - * @return QueryBuilder This QueryBuilder instance. + * @param DynamicOperandInterface $sort the ordering expression + * @param string $order the ordering direction */ - public function orderBy(DynamicOperandInterface $sort, $order = 'ASC') + public function orderBy(DynamicOperandInterface $sort, string $order = 'ASC'): static { $this->orderings = []; $this->addOrderBy($sort, $order); @@ -250,12 +205,8 @@ public function orderBy(DynamicOperandInterface $sort, $order = 'ASC') /** * Specifies one restriction (may be simple or composed). * Replaces any previously specified restrictions, if any. - * - * @param ConstraintInterface $constraint - * - * @return QueryBuilder This QueryBuilder instance. */ - public function where(ConstraintInterface $constraint) + public function where(ConstraintInterface $constraint): static { $this->state = self::STATE_DIRTY; $this->constraint = $constraint; @@ -265,10 +216,8 @@ public function where(ConstraintInterface $constraint) /** * Returns the constraint to apply. - * - * @return ConstraintInterface the constraint to be applied */ - public function getConstraint() + public function getConstraint(): ?ConstraintInterface { return $this->constraint; } @@ -285,12 +234,8 @@ public function getConstraint() * * If there is no previous constraint then it will simply store the * provided one - * - * @param ConstraintInterface $constraint - * - * @return QueryBuilder This QueryBuilder instance. */ - public function andWhere(ConstraintInterface $constraint) + public function andWhere(ConstraintInterface $constraint): static { $this->state = self::STATE_DIRTY; @@ -315,12 +260,8 @@ public function andWhere(ConstraintInterface $constraint) * * If there is no previous constraint then it will simply store the * provided one - * - * @param ConstraintInterface $constraint - * - * @return QueryBuilder This QueryBuilder instance. */ - public function orWhere(ConstraintInterface $constraint) + public function orWhere(ConstraintInterface $constraint): static { $this->state = self::STATE_DIRTY; @@ -334,23 +275,17 @@ public function orWhere(ConstraintInterface $constraint) } /** - * Returns the columns to be selected. - * - * @return ColumnInterface[] The columns to be selected + * @return ColumnInterface[] */ - public function getColumns() + public function getColumns(): array { return $this->columns; } /** - * Sets the columns to be selected. - * - * @param ColumnInterface[] $columns The columns to be selected - * - * @return QueryBuilder This QueryBuilder instance. + * @param ColumnInterface[] $columns */ - public function setColumns(array $columns) + public function setColumns(array $columns): static { $this->columns = $columns; @@ -360,14 +295,8 @@ public function setColumns(array $columns) /** * Identifies a property in the specified or default selector to include in the tabular view of query results. * Replaces any previously specified columns to be selected if any. - * - * @param string $selectorName - * @param string $propertyName - * @param string $columnName - * - * @return QueryBuilder This QueryBuilder instance. */ - public function select($selectorName, $propertyName, $columnName = null) + public function select(string $selectorName, string $propertyName, ?string $columnName = null): static { $this->state = self::STATE_DIRTY; $this->columns = [$this->qomFactory->column($selectorName, $propertyName, $columnName)]; @@ -377,14 +306,8 @@ public function select($selectorName, $propertyName, $columnName = null) /** * Adds a property in the specified or default selector to include in the tabular view of query results. - * - * @param string $selectorName - * @param string $propertyName - * @param string $columnName - * - * @return QueryBuilder This QueryBuilder instance. */ - public function addSelect($selectorName, $propertyName, $columnName = null) + public function addSelect(string $selectorName, string $propertyName, ?string $columnName = null): static { $this->state = self::STATE_DIRTY; @@ -396,12 +319,8 @@ public function addSelect($selectorName, $propertyName, $columnName = null) /** * Sets the default Selector or the node-tuple Source. Can be a selector * or a join. - * - * @param SourceInterface $source - * - * @return QueryBuilder This QueryBuilder instance. */ - public function from(SourceInterface $source) + public function from(SourceInterface $source): static { $this->state = self::STATE_DIRTY; $this->source = $source; @@ -412,9 +331,9 @@ public function from(SourceInterface $source) /** * Gets the default Selector. * - * @return SourceInterface The default selector. + * @return SourceInterface|null the default selector */ - public function getSource() + public function getSource(): ?SourceInterface { return $this->source; } @@ -422,14 +341,9 @@ public function getSource() /** * Performs an inner join between the stored source and the supplied source. * - * @param SourceInterface $rightSource - * @param JoinConditionInterface $joinCondition - * - * @throws RuntimeException if there is not an existing source. - * - * @return QueryBuilder This QueryBuilder instance. + * @throws \RuntimeException if there is not an existing source */ - public function join(SourceInterface $rightSource, JoinConditionInterface $joinCondition) + public function join(SourceInterface $rightSource, JoinConditionInterface $joinCondition): static { return $this->innerJoin($rightSource, $joinCondition); } @@ -437,14 +351,9 @@ public function join(SourceInterface $rightSource, JoinConditionInterface $joinC /** * Performs an inner join between the stored source and the supplied source. * - * @param SourceInterface $rightSource - * @param JoinConditionInterface $joinCondition - * - * @throws RuntimeException if there is not an existing source. - * - * @return QueryBuilder This QueryBuilder instance. + * @throws \RuntimeException if there is not an existing source */ - public function innerJoin(SourceInterface $rightSource, JoinConditionInterface $joinCondition) + public function innerJoin(SourceInterface $rightSource, JoinConditionInterface $joinCondition): static { return $this->joinWithType($rightSource, QueryObjectModelConstantsInterface::JCR_JOIN_TYPE_INNER, $joinCondition); } @@ -452,14 +361,9 @@ public function innerJoin(SourceInterface $rightSource, JoinConditionInterface $ /** * Performs an left outer join between the stored source and the supplied source. * - * @param SourceInterface $rightSource - * @param JoinConditionInterface $joinCondition - * - * @throws RuntimeException if there is not an existing source. - * - * @return QueryBuilder This QueryBuilder instance. + * @throws \RuntimeException if there is not an existing source */ - public function leftJoin(SourceInterface $rightSource, JoinConditionInterface $joinCondition) + public function leftJoin(SourceInterface $rightSource, JoinConditionInterface $joinCondition): static { return $this->joinWithType($rightSource, QueryObjectModelConstantsInterface::JCR_JOIN_TYPE_LEFT_OUTER, $joinCondition); } @@ -467,14 +371,9 @@ public function leftJoin(SourceInterface $rightSource, JoinConditionInterface $j /** * Performs a right outer join between the stored source and the supplied source. * - * @param SourceInterface $rightSource - * @param JoinConditionInterface $joinCondition - * - * @throws RuntimeException if there is not an existing source. - * - * @return QueryBuilder This QueryBuilder instance. + * @throws \RuntimeException if there is not an existing source */ - public function rightJoin(SourceInterface $rightSource, JoinConditionInterface $joinCondition) + public function rightJoin(SourceInterface $rightSource, JoinConditionInterface $joinCondition): static { return $this->joinWithType($rightSource, QueryObjectModelConstantsInterface::JCR_JOIN_TYPE_RIGHT_OUTER, $joinCondition); } @@ -482,18 +381,14 @@ public function rightJoin(SourceInterface $rightSource, JoinConditionInterface $ /** * Performs an join between the stored source and the supplied source. * - * @param SourceInterface $rightSource - * @param string $joinType as specified in PHPCR\Query\QOM\QueryObjectModelConstantsInterface - * @param JoinConditionInterface $joinCondition + * @param string $joinType as specified in PHPCR\Query\QOM\QueryObjectModelConstantsInterface * - * @throws RuntimeException if there is not an existing source. - * - * @return QueryBuilder This QueryBuilder instance. + * @throws \RuntimeException if there is not an existing source */ - public function joinWithType(SourceInterface $rightSource, $joinType, JoinConditionInterface $joinCondition) + public function joinWithType(SourceInterface $rightSource, string $joinType, JoinConditionInterface $joinCondition): static { if (!$this->source) { - throw new RuntimeException('Cannot perform a join without a previous call to from'); + throw new \RuntimeException('Cannot perform a join without a previous call to from'); } $this->state = self::STATE_DIRTY; @@ -504,12 +399,10 @@ public function joinWithType(SourceInterface $rightSource, $joinType, JoinCondit /** * Gets the query built. - * - * @return QueryObjectModelInterface */ - public function getQuery() + public function getQuery(): QueryObjectModelInterface { - if ($this->query !== null && $this->state === self::STATE_CLEAN) { + if (null !== $this->query && self::STATE_CLEAN === $this->state) { return $this->query; } @@ -529,12 +422,10 @@ public function getQuery() /** * Executes the query setting firstResult and maxResults. - * - * @return QueryResultInterface */ - public function execute() + public function execute(): QueryResultInterface { - if ($this->query === null || $this->state === self::STATE_DIRTY) { + if (null === $this->query || self::STATE_DIRTY === $this->state) { $this->query = $this->getQuery(); } @@ -547,39 +438,28 @@ public function execute() /** * Sets a query parameter for the query being constructed. - * - * @param string $key The parameter name. - * @param mixed $value The parameter value. - * - * @return QueryBuilder This QueryBuilder instance. */ - public function setParameter($key, $value) + public function setParameter(string $parameterName, mixed $parameterValue): static { - $this->params[$key] = $value; + $this->params[$parameterName] = $parameterValue; return $this; } /** * Gets a (previously set) query parameter of the query being constructed. - * - * @param string $key The key (name) of the bound parameter. - * - * @return mixed The value of the bound parameter. */ - public function getParameter($key) + public function getParameter(string $parameterName): mixed { - return isset($this->params[$key]) ? $this->params[$key] : null; + return $this->params[$parameterName] ?? null; } /** * Sets a collection of query parameters for the query being constructed. * - * @param array $params The query parameters to set. - * - * @return QueryBuilder This QueryBuilder instance. + * @param array $params the query parameters to set */ - public function setParameters(array $params) + public function setParameters(array $params): static { $this->params = $params; @@ -587,11 +467,9 @@ public function setParameters(array $params) } /** - * Gets all defined query parameters for the query being constructed. - * - * @return array The currently defined query parameters. + * @return array Map of parameter name => parameter value */ - public function getParameters() + public function getParameters(): array { return $this->params; } diff --git a/src/PHPCR/Util/QOM/Sql1Generator.php b/src/PHPCR/Util/QOM/Sql1Generator.php index 6c9927a2..452a164c 100644 --- a/src/PHPCR/Util/QOM/Sql1Generator.php +++ b/src/PHPCR/Util/QOM/Sql1Generator.php @@ -1,5 +1,7 @@ getPathForDescendantQuery($path); $sql1 = "jcr:path LIKE '".$path."'"; @@ -64,12 +55,9 @@ public function evalChildNode($path, $selectorName = null) /** * Emulate descendant query with LIKE query. * - * @param string $path * @param string|null $selectorName Unused - * - * @return string */ - public function evalDescendantNode($path, $selectorName = null) + public function evalDescendantNode(string $path, ?string $selectorName = null): string { $path = $this->getPathForDescendantQuery($path); @@ -80,13 +68,10 @@ public function evalDescendantNode($path, $selectorName = null) * PropertyExistence ::= * propertyName 'IS NOT NULL'. * - * @param string $selectorName declared to simplifiy interface - as there - * are no joins in SQL1 there is no need for a selector. - * @param string $propertyName - * - * @return string + * @param string|null $selectorName declared to simplifiy interface - as there + * are no joins in SQL1 there is no need for a selector */ - public function evalPropertyExistence($selectorName, $propertyName) + public function evalPropertyExistence(?string $selectorName, string $propertyName): string { return $propertyName.' IS NOT NULL'; } @@ -97,13 +82,9 @@ public function evalPropertyExistence($selectorName, $propertyName) * FullTextSearchExpression ')' * FullTextSearchExpression ::= BindVariable | ''' FullTextSearchLiteral '''. * - * @param string $selectorName unusued - * @param string $searchExpression - * @param string $propertyName - * - * @return string + * @param string $selectorName unusued */ - public function evalFullTextSearch($selectorName, $searchExpression, $propertyName = null) + public function evalFullTextSearch(string $selectorName, string $searchExpression, ?string $propertyName = null): string { $propertyName = $propertyName ?: '*'; @@ -116,22 +97,18 @@ public function evalFullTextSearch($selectorName, $searchExpression, $propertyNa /** * columns ::= (Column ',' {Column}) | '*'. - * - * @param $columns - * - * @return string */ - public function evalColumns($columns) + public function evalColumns(iterable $columns): string { if ((!is_array($columns) && !$columns instanceof \Countable) - || count($columns) === 0 + || 0 === count($columns) ) { return 's'; } $sql1 = ''; foreach ($columns as $column) { - if ($sql1 !== '') { + if ('' !== $sql1) { $sql1 .= ', '; } @@ -144,12 +121,9 @@ public function evalColumns($columns) /** * PropertyValue ::= propertyName. * - * @param string $propertyName - * @param string $selectorName unused in SQL1 - * - * @return string + * @param string|null $selectorName unused in SQL1 */ - public function evalPropertyValue($propertyName, $selectorName = null) + public function evalPropertyValue(string $propertyName, ?string $selectorName = null): string { return $propertyName; } @@ -160,13 +134,10 @@ public function evalPropertyValue($propertyName, $selectorName = null) * * No support for column name ('AS' columnName) in SQL1 * - * @param string $selectorName unused in SQL1 - * @param string $propertyName - * @param string $colname unused in SQL1 - * - * @return string + * @param string $selectorName unused in SQL1 + * @param string|null $colname unused in SQL1 */ - public function evalColumn($selectorName = null, $propertyName = null, $colname = null) + public function evalColumn(string $selectorName, ?string $propertyName = null, ?string $colname = null): string { return $propertyName; } @@ -174,12 +145,8 @@ public function evalColumn($selectorName = null, $propertyName = null, $colname /** * Path ::= simplePath * simplePath ::= A JCR Name that contains only SQL-legal characters. - * - * @param string $path - * - * @return string */ - public function evalPath($path) + public function evalPath(string $path): string { return $path; } @@ -189,7 +156,7 @@ public function evalPath($path) * * No explicit support, do some tricks where possible. */ - public function evalCastLiteral($literal, $type) + public function evalCastLiteral(string $literal, string $type): string { switch ($type) { case 'DATE': diff --git a/src/PHPCR/Util/QOM/Sql2Generator.php b/src/PHPCR/Util/QOM/Sql2Generator.php index 45fd7751..7c042f1d 100644 --- a/src/PHPCR/Util/QOM/Sql2Generator.php +++ b/src/PHPCR/Util/QOM/Sql2Generator.php @@ -1,5 +1,7 @@ addBracketsIfNeeded($nodeTypeName); @@ -41,15 +41,8 @@ public function evalSelector($nodeTypeName, $selectorName = null) * // If JoinType is omitted INNER is assumed. * left ::= Source * right ::= Source. - * - * @param string $left - * @param string $right - * @param string $joinCondition - * @param string $joinType - * - * @return string */ - public function evalJoin($left, $right, $joinCondition, $joinType = '') + public function evalJoin(string $left, string $right, string $joinCondition, string $joinType = ''): string { return "$left {$joinType}JOIN $right ON $joinCondition"; } @@ -59,23 +52,15 @@ public function evalJoin($left, $right, $joinCondition, $joinType = '') * Inner ::= 'INNER' * LeftOuter ::= 'LEFT OUTER' * RightOuter ::= 'RIGHT OUTER'. - * - * @param string $joinType - * - * @return string */ - public function evalJoinType($joinType) + public function evalJoinType(string $joinType): string { - switch ($joinType) { - case Constants::JCR_JOIN_TYPE_INNER: - return 'INNER '; - case Constants::JCR_JOIN_TYPE_LEFT_OUTER: - return 'LEFT OUTER '; - case Constants::JCR_JOIN_TYPE_RIGHT_OUTER: - return 'RIGHT OUTER '; - } - - return $joinType; + return match ($joinType) { + Constants::JCR_JOIN_TYPE_INNER => 'INNER ', + Constants::JCR_JOIN_TYPE_LEFT_OUTER => 'LEFT OUTER ', + Constants::JCR_JOIN_TYPE_RIGHT_OUTER => 'RIGHT OUTER ', + default => $joinType, + }; } /** @@ -85,15 +70,8 @@ public function evalJoinType($joinType) * selector2Name ::= selectorName * property1Name ::= propertyName * property2Name ::= propertyName. - * - * @param string $sel1Name - * @param string $prop1Name - * @param string $sel2Name - * @param string $prop2Name - * - * @return string */ - public function evalEquiJoinCondition($sel1Name, $prop1Name, $sel2Name, $prop2Name) + public function evalEquiJoinCondition(string $sel1Name, string $prop1Name, string $sel2Name, string $prop2Name): string { return $this->evalPropertyValue($prop1Name, $sel1Name).'='.$this->evalPropertyValue($prop2Name, $sel2Name); } @@ -104,14 +82,8 @@ public function evalEquiJoinCondition($sel1Name, $prop1Name, $sel2Name, $prop2Na * selector2Name * [',' selector2Path] ')' * selector2Path ::= Path. - * - * @param string $sel1Name - * @param string $sel2Name - * @param string $sel2Path - * - * @return string */ - public function evalSameNodeJoinCondition($sel1Name, $sel2Name, $sel2Path = null) + public function evalSameNodeJoinCondition(string $sel1Name, string $sel2Name, ?string $sel2Path = null): string { $sql2 = 'ISSAMENODE(' .$this->addBracketsIfNeeded($sel1Name).', ' @@ -130,13 +102,8 @@ public function evalSameNodeJoinCondition($sel1Name, $sel2Name, $sel2Path = null * parentSelectorName ')' * childSelectorName ::= selectorName * parentSelectorName ::= selectorName. - * - * @param string $childSelectorName - * @param string $parentSelectorName - * - * @return string */ - public function evalChildNodeJoinCondition($childSelectorName, $parentSelectorName) + public function evalChildNodeJoinCondition(string $childSelectorName, string $parentSelectorName): string { return 'ISCHILDNODE(' .$this->addBracketsIfNeeded($childSelectorName).', ' @@ -149,13 +116,8 @@ public function evalChildNodeJoinCondition($childSelectorName, $parentSelectorNa * ancestorSelectorName ')' * descendantSelectorName ::= selectorName * ancestorSelectorName ::= selectorName. - * - * @param string $descendantSelectorName - * @param string $ancestorselectorName - * - * @return string */ - public function evalDescendantNodeJoinCondition($descendantSelectorName, $ancestorselectorName) + public function evalDescendantNodeJoinCondition(string $descendantSelectorName, string $ancestorselectorName): string { return 'ISDESCENDANTNODE(' .$this->addBracketsIfNeeded($descendantSelectorName).', ' @@ -164,13 +126,8 @@ public function evalDescendantNodeJoinCondition($descendantSelectorName, $ancest /** * SameNode ::= 'ISSAMENODE(' [selectorName ','] Path ')'. - * - * @param string $path - * @param string $selectorName - * - * @return string */ - public function evalSameNode($path, $selectorName = null) + public function evalSameNode(string $path, ?string $selectorName = null): string { $sql2 = 'ISSAMENODE('; $sql2 .= null === $selectorName ? $path : $this->addBracketsIfNeeded($selectorName).', '.$path; @@ -181,13 +138,8 @@ public function evalSameNode($path, $selectorName = null) /** * SameNode ::= 'ISCHILDNODE(' [selectorName ','] Path ')'. - * - * @param string $path - * @param string $selectorName - * - * @return string */ - public function evalChildNode($path, $selectorName = null) + public function evalChildNode(string $path, ?string $selectorName = null): string { $sql2 = 'ISCHILDNODE('; $sql2 .= null === $selectorName ? $path : $this->addBracketsIfNeeded($selectorName).', '.$path; @@ -198,13 +150,8 @@ public function evalChildNode($path, $selectorName = null) /** * SameNode ::= 'ISDESCENDANTNODE(' [selectorName ','] Path ')'. - * - * @param string $path - * @param string $selectorName - * - * @return string */ - public function evalDescendantNode($path, $selectorName = null) + public function evalDescendantNode(string $path, ?string $selectorName = null): string { $sql2 = 'ISDESCENDANTNODE('; $sql2 .= null === $selectorName ? $path : $this->addBracketsIfNeeded($selectorName).', '.$path; @@ -219,13 +166,8 @@ public function evalDescendantNode($path, $selectorName = null) * propertyName 'IS NOT NULL' If only one * selector exists in * this query. - * - * @param $selectorName - * @param $propertyName - * - * @return string */ - public function evalPropertyExistence($selectorName, $propertyName) + public function evalPropertyExistence(?string $selectorName, string $propertyName): string { return $this->evalPropertyValue($propertyName, $selectorName).' IS NOT NULL'; } @@ -236,14 +178,8 @@ public function evalPropertyExistence($selectorName, $propertyName) * selectorName'.*') ',' * FullTextSearchExpression ')' * FullTextSearchExpression ::= BindVariable | ''' FullTextSearchLiteral '''. - * - * @param string $selectorName - * @param string $searchExpression - * @param string $propertyName - * - * @return string */ - public function evalFullTextSearch($selectorName, $searchExpression, $propertyName = null) + public function evalFullTextSearch(string $selectorName, string $searchExpression, ?string $propertyName = null): string { $propertyName = $propertyName ?: '*'; @@ -256,64 +192,43 @@ public function evalFullTextSearch($selectorName, $searchExpression, $propertyNa /** * Length ::= 'LENGTH(' PropertyValue ')'. - * - * @param string $propertyValue - * - * @return string */ - public function evalLength($propertyValue) + public function evalLength(string $propertyValue): string { return "LENGTH($propertyValue)"; } /** * NodeName ::= 'NAME(' [selectorName] ')'. - * - * @param string $selectorValue - * - * @return string */ - public function evalNodeName($selectorValue = null) + public function evalNodeName(?string $selectorValue = null): string { return "NAME($selectorValue)"; } /** * NodeLocalName ::= 'LOCALNAME(' [selectorName] ')'. - * - * @param string $selectorValue - * - * @return string */ - public function evalNodeLocalName($selectorValue = null) + public function evalNodeLocalName(?string $selectorValue = null): string { return "LOCALNAME($selectorValue)"; } /** * FullTextSearchScore ::= 'SCORE(' [selectorName] ')'. - * - * @param string $selectorValue - * - * @return string */ - public function evalFullTextSearchScore($selectorValue = null) + public function evalFullTextSearchScore(?string $selectorValue = null): string { return "SCORE($selectorValue)"; } /** * PropertyValue ::= [selectorName'.'] propertyName // If only one selector exists. - * - * @param string $propertyName - * @param string $selectorName - * - * @return string */ - public function evalPropertyValue($propertyName, $selectorName = null) + public function evalPropertyValue(string $propertyName, ?string $selectorName = null): string { $sql2 = null !== $selectorName ? $this->addBracketsIfNeeded($selectorName).'.' : ''; - if ('*' !== $propertyName && substr($propertyName, 0, 1) !== '[') { + if ('*' !== $propertyName && !str_starts_with($propertyName, '[')) { $propertyName = "[$propertyName]"; } $sql2 .= $propertyName; @@ -323,22 +238,18 @@ public function evalPropertyValue($propertyName, $selectorName = null) /** * columns ::= (Column ',' {Column}) | '*'. - * - * @param $columns - * - * @return string */ - public function evalColumns($columns) + public function evalColumns(iterable $columns): string { if ((!is_array($columns) && !$columns instanceof \Countable) - || count($columns) === 0 + || 0 === count($columns) ) { return '*'; } $sql2 = ''; foreach ($columns as $column) { - if ($sql2 !== '') { + if ('' !== $sql2) { $sql2 .= ', '; } @@ -355,14 +266,8 @@ public function evalColumns($columns) * selectorName ::= Name * propertyName ::= Name * columnName ::= Name. - * - * @param string $selectorName - * @param string $propertyName - * @param string $colname - * - * @return string */ - public function evalColumn($selectorName, $propertyName = null, $colname = null) + public function evalColumn(string $selectorName, ?string $propertyName = null, ?string $colname = null): string { $sql2 = ''; if (null !== $selectorName && null === $propertyName && null === $colname) { @@ -382,20 +287,16 @@ public function evalColumn($selectorName, $propertyName = null, $colname = null) * Path ::= '[' quotedPath ']' | '[' simplePath ']' | simplePath * quotedPath ::= A JCR Path that contains non-SQL-legal characters * simplePath ::= A JCR Name that contains only SQL-legal characters. - * - * @param string $path - * - * @return string */ - public function evalPath($path) + public function evalPath(string $path): string { if (!$path) { return $path; } $sql2 = $path; // only ensure proper quoting if the user did not quote himself, we trust him to get it right if he did. - if (strpos($path, '[') !== 0 && substr($path, -1) !== ']') { - if (false !== strpos($sql2, ' ') || false !== strpos($sql2, '.')) { + if (!str_starts_with($path, '[') && !str_ends_with($path, ']')) { + if (str_contains($sql2, ' ') || str_contains($sql2, '.')) { $sql2 = '"'.$sql2.'"'; } $sql2 = '['.$sql2.']'; @@ -409,7 +310,7 @@ public function evalPath($path) * * CastLiteral ::= 'CAST(' UncastLiteral ' AS ' PropertyType ')' */ - public function evalCastLiteral($literal, $type) + public function evalCastLiteral(string $literal, string $type): string { return "CAST('$literal' AS $type)"; } @@ -417,15 +318,13 @@ public function evalCastLiteral($literal, $type) /** * Add square brackets around a selector if needed. * - * @param string $selector - * * @return string $selector guaranteed to have [] around it if needed */ - private function addBracketsIfNeeded($selector) + private function addBracketsIfNeeded(string $selector): string { - if (substr($selector, 0, 1) !== '[' - && substr($selector, -1) !== ']' - && false !== strpos($selector, ':') + if (!str_starts_with($selector, '[') + && !str_ends_with($selector, ']') + && str_contains($selector, ':') ) { return "[$selector]"; } diff --git a/src/PHPCR/Util/QOM/Sql2Scanner.php b/src/PHPCR/Util/QOM/Sql2Scanner.php index a4c41078..0ec2a830 100644 --- a/src/PHPCR/Util/QOM/Sql2Scanner.php +++ b/src/PHPCR/Util/QOM/Sql2Scanner.php @@ -1,5 +1,7 @@ sql2 = $sql2; $this->tokens = $this->scan($this->sql2); @@ -49,10 +42,8 @@ public function __construct($sql2) * Return an empty string when there are no more tokens. * * @param int $offset number of tokens to look ahead - defaults to 0, the current token - * - * @return string */ - public function lookupNextToken($offset = 0) + public function lookupNextToken(int $offset = 0): string { if ($this->curpos + $offset < count($this->tokens)) { return trim($this->tokens[$this->curpos + $offset]); @@ -64,14 +55,12 @@ public function lookupNextToken($offset = 0) /** * Get the next token and remove it from the queue. * Return an empty string when there are no more tokens. - * - * @return string */ - public function fetchNextToken() + public function fetchNextToken(): string { $token = $this->lookupNextToken(); - if ($token !== '') { - $this->curpos += 1; + if ('' !== $token) { + ++$this->curpos; } return trim($token); @@ -82,12 +71,11 @@ public function fetchNextToken() * not the case. The equality test is done case sensitively/insensitively * depending on the second parameter. * - * @param string $token The expected token - * @param bool $case_insensitive + * @param string $token The expected token * * @throws InvalidQueryException */ - public function expectToken($token, $case_insensitive = true) + public function expectToken(string $token, bool $case_insensitive = true): void { $nextToken = $this->fetchNextToken(); if (!$this->tokenIs($nextToken, $token, $case_insensitive)) { @@ -99,14 +87,11 @@ public function expectToken($token, $case_insensitive = true) * Expect the next tokens to be the one given in the array of tokens and * throws an exception if it's not the case. * - * @param array $tokens - * @param bool $case_insensitive - * * @throws InvalidQueryException * * @see expectToken */ - public function expectTokens($tokens, $case_insensitive = true) + public function expectTokens(array $tokens, bool $case_insensitive = true): void { foreach ($tokens as $token) { $this->expectToken($token, $case_insensitive); @@ -115,14 +100,8 @@ public function expectTokens($tokens, $case_insensitive = true) /** * Test the equality of two tokens. - * - * @param string $token - * @param string $value - * @param bool $case_insensitive - * - * @return bool */ - public function tokenIs($token, $value, $case_insensitive = true) + public function tokenIs(string $token, string $value, bool $case_insensitive = true): bool { if ($case_insensitive) { $test = strtoupper($token) === strtoupper($value); @@ -150,17 +129,18 @@ protected function scan($sql2) $isEscaped = false; $escapedQuotesCount = 0; $splitString = \str_split($sql2); - for ($index = 0; $index < count($splitString); $index++) { + $splitStringCount = count($splitString); + for ($index = 0; $index < $splitStringCount; ++$index) { $character = $splitString[$index]; if (!$stringStartCharacter && in_array($character, [' ', "\t", "\n", "\r"], true)) { - if ($currentToken !== '') { + if ('' !== $currentToken) { $tokens[] = $currentToken; } $currentToken = ''; continue; } if (!$stringStartCharacter && in_array($character, $tokenEndChars, true)) { - if ($currentToken !== '') { + if ('' !== $currentToken) { $tokens[] = $currentToken; } $tokens[] = $character; @@ -169,8 +149,8 @@ protected function scan($sql2) } // Handling the squared brackets in queries - if (!$isEscaped && $character === '[') { - if ($currentToken !== '') { + if (!$isEscaped && '[' === $character) { + if ('' !== $currentToken) { $tokens[] = $currentToken; } $stringSize = $this->parseBrackets($sql2, $index); @@ -188,13 +168,13 @@ protected function scan($sql2) // Checking if the previous or next value is a ' to handle the weird SQL strings // This will not check if the amount of quotes is even $nextCharacter = $splitString[$index + 1] ?? ''; - if ($character === "'" && $nextCharacter === "'") { + if ("'" === $character && "'" === $nextCharacter) { $isEscaped = true; - $escapedQuotesCount++; + ++$escapedQuotesCount; continue; } // If the escaped quotes are not paired up. eg. "I'''m cool" would be a parsing error - if ($escapedQuotesCount % 2 == 1 && $stringStartCharacter !== "'") { + if (1 === $escapedQuotesCount % 2 && "'" !== $stringStartCharacter) { throw new InvalidQueryException("Syntax error: Number of single quotes to be even: $currentToken"); } if ($character === $stringStartCharacter) { @@ -208,14 +188,14 @@ protected function scan($sql2) // When tokenizing `AS"abc"` add the current token (AS) as token already if (strlen($currentToken) > 1) { - $tokens[] = substr($currentToken, 0, strlen($currentToken) - 1); + $tokens[] = substr($currentToken, 0, -1); $currentToken = $character; } } } - $isEscaped = $character === '\\'; + $isEscaped = '\\' === $character; } - if ($currentToken !== '') { + if ('' !== $currentToken) { $tokens[] = $currentToken; } diff --git a/src/PHPCR/Util/QOM/Sql2ToQomQueryConverter.php b/src/PHPCR/Util/QOM/Sql2ToQomQueryConverter.php index 76aca66b..e0bd27b3 100644 --- a/src/PHPCR/Util/QOM/Sql2ToQomQueryConverter.php +++ b/src/PHPCR/Util/QOM/Sql2ToQomQueryConverter.php @@ -1,17 +1,17 @@ factory = $factory; $this->valueConverter = $valueConverter ?: new ValueConverter(); @@ -93,10 +74,8 @@ public function __construct(QueryObjectModelFactoryInterface $factory, ValueConv * @param string $sql2 * * @throws InvalidQueryException - * - * @return QueryObjectModelInterface */ - public function parse($sql2) + public function parse($sql2): QueryObjectModelInterface { $this->implicitSelectorName = null; $this->sql2 = $sql2; @@ -106,7 +85,7 @@ public function parse($sql2) $constraint = null; $orderings = []; - while ($this->scanner->lookupNextToken() !== '') { + while ('' !== $this->scanner->lookupNextToken()) { switch (strtoupper($this->scanner->lookupNextToken())) { case 'SELECT': $this->scanner->expectToken('SELECT'); @@ -142,10 +121,8 @@ public function parse($sql2) /** * 6.7.2. Source * Parse an SQL2 source definition and return the corresponding QOM Source. - * - * @return SourceInterface */ - protected function parseSource() + protected function parseSource(): JoinInterface|SourceInterface|SelectorInterface { $selector = $this->parseSelector(); @@ -163,10 +140,8 @@ protected function parseSource() /** * 6.7.3. Selector * Parse an SQL2 selector and return a QOM\SelectorInterface. - * - * @return SelectorInterface */ - protected function parseSelector() + protected function parseSelector(): SelectorInterface { $nodetype = $this->fetchTokenWithoutBrackets(); @@ -184,10 +159,8 @@ protected function parseSelector() /** * 6.7.4. Name. - * - * @return string */ - protected function parseName() + protected function parseName(): string { return $this->scanner->fetchNextToken(); } @@ -198,10 +171,8 @@ protected function parseName() * Parse an SQL2 join source and return a QOM\Join. * * @param SourceInterface $leftSelector the left selector as it has been read by parseSource - * - * @return JoinInterface */ - protected function parseJoin(SourceInterface $leftSelector) + protected function parseJoin(SourceInterface $leftSelector): JoinInterface { $joinType = $this->parseJoinType(); $right = $this->parseSelector(); @@ -214,10 +185,8 @@ protected function parseJoin(SourceInterface $leftSelector) * 6.7.6. Join type. * * @throws InvalidQueryException - * - * @return string */ - protected function parseJoinType() + protected function parseJoinType(): string { $joinType = Constants::JCR_JOIN_TYPE_INNER; $token = $this->scanner->fetchNextToken(); @@ -247,10 +216,8 @@ protected function parseJoinType() /** * 6.7.7. JoinCondition * Parse an SQL2 join condition and return a JoinConditionInterface. - * - * @return JoinConditionInterface */ - protected function parseJoinCondition() + protected function parseJoinCondition(): JoinConditionInterface { $this->scanner->expectToken('ON'); @@ -273,14 +240,12 @@ protected function parseJoinCondition() /** * 6.7.8. EquiJoinCondition * Parse an SQL2 equijoin condition and return a EquiJoinConditionInterface. - * - * @return EquiJoinConditionInterface */ - protected function parseEquiJoin() + protected function parseEquiJoin(): EquiJoinConditionInterface { - list($selectorName1, $prop1) = $this->parseIdentifier(); + [$selectorName1, $prop1] = $this->parseIdentifier(); $this->scanner->expectToken('='); - list($selectorName2, $prop2) = $this->parseIdentifier(); + [$selectorName2, $prop2] = $this->parseIdentifier(); return $this->factory->equiJoinCondition($selectorName1, $prop1, $selectorName2, $prop2); } @@ -288,10 +253,8 @@ protected function parseEquiJoin() /** * 6.7.9 SameNodeJoinCondition * Parse an SQL2 same node join condition and return a SameNodeJoinConditionInterface. - * - * @return SameNodeJoinConditionInterface */ - protected function parseSameNodeJoinCondition() + protected function parseSameNodeJoinCondition(): SameNodeJoinConditionInterface { $this->scanner->expectTokens(['ISSAMENODE', '(']); $selectorName1 = $this->fetchTokenWithoutBrackets(); @@ -314,10 +277,8 @@ protected function parseSameNodeJoinCondition() /** * 6.7.10 ChildNodeJoinCondition * Parse an SQL2 child node join condition and return a ChildNodeJoinConditionInterface. - * - * @return ChildNodeJoinConditionInterface */ - protected function parseChildNodeJoinCondition() + protected function parseChildNodeJoinCondition(): ChildNodeJoinConditionInterface { $this->scanner->expectTokens(['ISCHILDNODE', '(']); $child = $this->fetchTokenWithoutBrackets(); @@ -331,10 +292,8 @@ protected function parseChildNodeJoinCondition() /** * 6.7.11 DescendantNodeJoinCondition * Parse an SQL2 descendant node join condition and return a DescendantNodeJoinConditionInterface. - * - * @return DescendantNodeJoinConditionInterface */ - protected function parseDescendantNodeJoinCondition() + protected function parseDescendantNodeJoinCondition(): DescendantNodeJoinConditionInterface { $this->scanner->expectTokens(['ISDESCENDANTNODE', '(']); $descendant = $this->fetchTokenWithoutBrackets(); @@ -349,21 +308,19 @@ protected function parseDescendantNodeJoinCondition() * 6.7.13 And * 6.7.14 Or. * - * @param ConstraintInterface $lhs Left hand side - * @param int $minprec Precedence + * @param ConstraintInterface|null $lhs Left hand side + * @param int $minprec Precedence * - * @throws Exception - * - * @return ConstraintInterface + * @throws \Exception */ - protected function parseConstraint($lhs = null, $minprec = 0) + protected function parseConstraint(?ConstraintInterface $lhs = null, int $minprec = 0): ?ConstraintInterface { - if ($lhs === null) { + if (null === $lhs) { $lhs = $this->parsePrimaryConstraint(); } $opprec = [ - 'OR' => 1, + 'OR' => 1, 'AND' => 2, ]; @@ -391,7 +348,7 @@ protected function parseConstraint($lhs = null, $minprec = 0) // this only happens if the operator is // in the $opprec-array but there is no // "elseif"-branch here for this operator. - throw new Exception("Internal error: No action is defined for operator '$op'"); + throw new \Exception("Internal error: No action is defined for operator '$op'"); } $op = strtoupper($this->scanner->lookupNextToken()); @@ -402,10 +359,8 @@ protected function parseConstraint($lhs = null, $minprec = 0) /** * 6.7.12 Constraint. - * - * @return ConstraintInterface */ - protected function parsePrimaryConstraint() + protected function parsePrimaryConstraint(): ConstraintInterface { $constraint = null; $token = $this->scanner->lookupNextToken(); @@ -442,14 +397,14 @@ protected function parsePrimaryConstraint() } } - if ($constraint === null) { + if (null === $constraint) { // It's not a property existence neither, then it's a comparison $constraint = $this->parseComparison(); } } // No constraint read, - if ($constraint === null) { + if (null === $constraint) { throw new InvalidQueryException("Syntax error: constraint expected in '{$this->sql2}'"); } @@ -458,10 +413,8 @@ protected function parsePrimaryConstraint() /** * 6.7.15 Not. - * - * @return NotInterface */ - protected function parseNot() + protected function parseNot(): NotInterface { $this->scanner->expectToken('NOT'); @@ -472,17 +425,10 @@ protected function parseNot() * 6.7.16 Comparison. * * @throws InvalidQueryException - * - * @return ComparisonInterface */ - protected function parseComparison() + protected function parseComparison(): ComparisonInterface { $op1 = $this->parseDynamicOperand(); - - if (null === $op1) { - throw new InvalidQueryException("Syntax error: dynamic operator expected in '{$this->sql2}'"); - } - $operator = $this->parseOperator(); $op2 = $this->parseStaticOperand(); @@ -494,7 +440,7 @@ protected function parseComparison() * * @return string a constant from QueryObjectModelConstantsInterface */ - protected function parseOperator() + protected function parseOperator(): string { $token = $this->scanner->fetchNextToken(); switch (strtoupper($token)) { @@ -519,12 +465,10 @@ protected function parseOperator() /** * 6.7.18 PropertyExistence. - * - * @return ConstraintInterface */ - protected function parsePropertyExistence() + protected function parsePropertyExistence(): ConstraintInterface { - list($selectorName, $prop) = $this->parseIdentifier(); + [$selectorName, $prop] = $this->parseIdentifier(); $this->scanner->expectToken('IS'); $token = $this->scanner->lookupNextToken(); @@ -541,14 +485,12 @@ protected function parsePropertyExistence() /** * 6.7.19 FullTextSearch. - * - * @return FullTextSearchInterface */ - protected function parseFullTextSearch() + protected function parseFullTextSearch(): FullTextSearchInterface { $this->scanner->expectTokens(['CONTAINS', '(']); - list($selectorName, $propertyName) = $this->parseIdentifier(); + [$selectorName, $propertyName] = $this->parseIdentifier(); $this->scanner->expectToken(','); $expression = $this->parseLiteralValue(); $this->scanner->expectToken(')'); @@ -559,7 +501,7 @@ protected function parseFullTextSearch() /** * 6.7.20 SameNode. */ - protected function parseSameNode() + protected function parseSameNode(): SameNodeInterface { $this->scanner->expectTokens(['ISSAMENODE', '(']); if ($this->scanner->tokenIs($this->scanner->lookupNextToken(1), ',')) { @@ -578,7 +520,7 @@ protected function parseSameNode() /** * 6.7.21 ChildNode. */ - protected function parseChildNode() + protected function parseChildNode(): ChildNodeInterface { $this->scanner->expectTokens(['ISCHILDNODE', '(']); if ($this->scanner->tokenIs($this->scanner->lookupNextToken(1), ',')) { @@ -597,7 +539,7 @@ protected function parseChildNode() /** * 6.7.22 DescendantNode. */ - protected function parseDescendantNode() + protected function parseDescendantNode(): DescendantNodeInterface { $this->scanner->expectTokens(['ISDESCENDANTNODE', '(']); if ($this->scanner->tokenIs($this->scanner->lookupNextToken(1), ',')) { @@ -623,7 +565,7 @@ protected function parseDescendantNode() protected function parsePath() { $path = $this->parseLiteralValue(); - if (substr($path, 0, 1) === '[' && substr($path, -1) === ']') { + if (str_starts_with($path, '[') && str_ends_with($path, ']')) { $path = substr($path, 1, -1); } @@ -634,13 +576,11 @@ protected function parsePath() * Parse an SQL2 static operand * 6.7.35 BindVariable * 6.7.36 Prefix. - * - * @return StaticOperandInterface */ - protected function parseStaticOperand() + protected function parseStaticOperand(): StaticOperandInterface { $token = $this->scanner->lookupNextToken(); - if (substr($token, 0, 1) === '$') { + if (str_starts_with($token, '$')) { return $this->factory->bindVariable(substr($this->scanner->fetchNextToken(), 1)); } @@ -656,10 +596,8 @@ protected function parseStaticOperand() * 6.7.32 LowerCase * 6.7.33 UpperCase * Parse an SQL2 dynamic operand. - * - * @return DynamicOperandInterface */ - protected function parseDynamicOperand() + protected function parseDynamicOperand(): DynamicOperandInterface|PropertyValueInterface { $token = $this->scanner->lookupNextToken(); @@ -738,20 +676,18 @@ protected function parseDynamicOperand() /** * 6.7.27 PropertyValue * Parse an SQL2 property value. - * - * @return PropertyValueInterface */ - protected function parsePropertyValue() + protected function parsePropertyValue(): PropertyValueInterface { - list($selectorName, $prop) = $this->parseIdentifier(); + [$selectorName, $prop] = $this->parseIdentifier(); return $this->factory->propertyValue($selectorName, $prop); } - protected function parseCastLiteral($token) + protected function parseCastLiteral($token): mixed { if (!$this->scanner->tokenIs($token, 'CAST')) { - throw new LogicException('parseCastLiteral when not a CAST'); + throw new \LogicException('parseCastLiteral when not a CAST'); } $this->scanner->expectToken('('); @@ -772,7 +708,7 @@ protected function parseCastLiteral($token) try { $typeValue = PropertyType::valueFromName($type); - } catch (InvalidArgumentException $e) { + } catch (\InvalidArgumentException $e) { throw new InvalidQueryException("Syntax error: attempting to cast to an invalid type '$type'"); } @@ -780,7 +716,7 @@ protected function parseCastLiteral($token) try { $token = $this->valueConverter->convertType($token, $typeValue, PropertyType::STRING); - } catch (Exception $e) { + } catch (\Exception $e) { throw new InvalidQueryException("Syntax error: attempting to cast string '$token' to type '$type'"); } @@ -790,10 +726,8 @@ protected function parseCastLiteral($token) /** * 6.7.34 Literal * Parse an SQL2 literal value. - * - * @return mixed */ - protected function parseLiteralValue() + protected function parseLiteralValue(): mixed { $token = $this->scanner->fetchNextToken(); if ($this->scanner->tokenIs($token, 'CAST')) { @@ -806,19 +740,18 @@ protected function parseLiteralValue() $quotesUsed = $token[0]; $token = substr($token, 1, -1); // Unescape quotes - $token = str_replace('\\'.$quotesUsed, $quotesUsed, $token); - $token = str_replace("''", "'", $token); + $token = str_replace(['\\'.$quotesUsed, "''"], [$quotesUsed, "'"], $token); if (preg_match('/^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d+)?$/', $token)) { if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $token)) { $token .= ' 00:00:00'; } - $token = DateTime::createFromFormat('Y-m-d H:i:s', $token); + $token = \DateTime::createFromFormat('Y-m-d H:i:s', $token); } } elseif (is_numeric($token)) { - $token = strpos($token, '.') === false ? (int) $token : (float) $token; - } elseif ($token === 'true') { + $token = !str_contains($token, '.') ? (int) $token : (float) $token; + } elseif ('true' === $token) { $token = true; - } elseif ($token === 'false') { + } elseif ('false' === $token) { $token = false; } @@ -828,7 +761,7 @@ protected function parseLiteralValue() /** * 6.7.37 Ordering. */ - protected function parseOrderings() + protected function parseOrderings(): array { $orderings = []; $continue = true; @@ -847,10 +780,8 @@ protected function parseOrderings() /** * 6.7.38 Order. - * - * @return OrderingInterface */ - protected function parseOrdering() + protected function parseOrdering(): OrderingInterface { $operand = $this->parseDynamicOperand(); $token = $this->scanner->lookupNextToken(); @@ -880,10 +811,10 @@ protected function parseOrdering() * * @return array of array */ - protected function scanColumns() + protected function scanColumns(): array { // Wildcard - if ($this->scanner->lookupNextToken() === '*') { + if ('*' === $this->scanner->lookupNextToken()) { $this->scanner->fetchNextToken(); return []; @@ -896,7 +827,7 @@ protected function scanColumns() $columns[] = $this->scanColumn(); // Are there more columns? - if ($this->scanner->lookupNextToken() !== ',') { + if (',' !== $this->scanner->lookupNextToken()) { $hasNext = false; } else { $this->scanner->fetchNextToken(); @@ -909,11 +840,9 @@ protected function scanColumns() /** * Build the columns from the scanned column data. * - * @param array $data - * * @return ColumnInterface[] */ - protected function buildColumns($data) + protected function buildColumns(array $data): array { $columns = []; foreach ($data as $col) { @@ -926,14 +855,12 @@ protected function buildColumns($data) /** * Get the next token and make sure to remove the brackets if the token is * in the [ns:name] notation. - * - * @return string */ - private function fetchTokenWithoutBrackets() + private function fetchTokenWithoutBrackets(): string { $token = $this->scanner->fetchNextToken(); - if (substr($token, 0, 1) === '[' && substr($token, -1) === ']') { + if (str_starts_with($token, '[') && str_ends_with($token, ']')) { // Remove brackets around the selector name $token = substr($token, 1, -1); } @@ -944,17 +871,17 @@ private function fetchTokenWithoutBrackets() /** * Parse something that is expected to be a property identifier. * - * @param bool $checkSelector whether we need to ensure a valid selector. + * @param bool $checkSelector whether we need to ensure a valid selector * - * @return array with selectorName and propertyName. If no selectorName is - * specified, defaults to $this->defaultSelectorName + * @return string[] with selectorName and propertyName. If no selectorName is + * specified, defaults to $this->defaultSelectorName */ - private function parseIdentifier($checkSelector = true) + private function parseIdentifier(bool $checkSelector = true): array { $token = $this->fetchTokenWithoutBrackets(); // selector.property - if ($this->scanner->lookupNextToken() === '.') { + if ('.' === $this->scanner->lookupNextToken()) { $selectorName = $token; $this->scanner->fetchNextToken(); $propertyName = $this->fetchTokenWithoutBrackets(); @@ -973,11 +900,9 @@ private function parseIdentifier($checkSelector = true) /** * Add a selector name to the known selector names. * - * @param string $selectorName - * * @throws InvalidQueryException */ - protected function updateImplicitSelectorName($selectorName) + protected function updateImplicitSelectorName(string $selectorName): void { if (null === $this->implicitSelectorName) { $this->implicitSelectorName = $selectorName; @@ -994,20 +919,16 @@ protected function updateImplicitSelectorName($selectorName) /** * Ensure that the parsedName is a valid selector, or return the implicit - * selector if its non-ambigous. - * - * @param string|null $parsedName + * selector if its non-ambiguous. * * @throws InvalidQueryException if there was no explicit selector and - * there is more than one selector available. - * - * @return string the selector to use + * there is more than one selector available */ - protected function ensureSelectorName($parsedName) + protected function ensureSelectorName(?string $parsedName): ?string { if (null !== $parsedName) { - if (is_array($this->implicitSelectorName) && !isset($this->implicitSelectorName[$parsedName]) - || !is_array($this->implicitSelectorName) && $this->implicitSelectorName !== $parsedName + if ((is_array($this->implicitSelectorName) && !isset($this->implicitSelectorName[$parsedName])) + || (!is_array($this->implicitSelectorName) && $this->implicitSelectorName !== $parsedName) ) { throw new InvalidQueryException("Unknown selector $parsedName in '{$this->sql2}'"); } @@ -1023,12 +944,10 @@ protected function ensureSelectorName($parsedName) /** * Scan a single SQL2 column definition and return an array of information. - * - * @return array */ - protected function scanColumn() + protected function scanColumn(): array { - list($selectorName, $propertyName) = $this->parseIdentifier(false); + [$selectorName, $propertyName] = $this->parseIdentifier(false); // AS name if ($this->scanner->tokenIs($this->scanner->lookupNextToken(), 'AS')) { @@ -1044,13 +963,11 @@ protected function scanColumn() /** * Build a single SQL2 column definition. * - * @param array $data with selector name, property name and column name. - * - * @return ColumnInterface + * @param array $data with selector name, property name and column name */ - protected function buildColumn(array $data) + protected function buildColumn(array $data): ColumnInterface { - list($selectorName, $propertyName, $columnName) = $data; + [$selectorName, $propertyName, $columnName] = $data; $selectorName = $this->ensureSelectorName($selectorName); return $this->factory->column($selectorName, $propertyName, $columnName); diff --git a/src/PHPCR/Util/TraversingItemVisitor.php b/src/PHPCR/Util/TraversingItemVisitor.php index 713df4c8..4707e962 100644 --- a/src/PHPCR/Util/TraversingItemVisitor.php +++ b/src/PHPCR/Util/TraversingItemVisitor.php @@ -1,5 +1,7 @@ breadthFirst = $breadthFirst; $this->maxDepth = $maxDepth; - if ($this->breadthFirst === true) { - $this->currentQueue = new SplQueue(); - $this->nextQueue = new SplQueue(); + if (true === $this->breadthFirst) { + $this->currentQueue = new \SplQueue(); + $this->nextQueue = new \SplQueue(); } $this->currentDepth = 0; } /** * Update the current depth level for indention. - * - * @param int $level */ - public function setLevel($level) + public function setLevel(int $level): void { $this->currentDepth = $level; } @@ -109,30 +94,30 @@ public function setLevel($level) * visited. * * @param ItemInterface $item the Item that is accepting this - * visitor. + * visitor * @param int $depth hierarchy level of this node (the root node starts - * at depth 0). + * at depth 0) * - * @throws RepositoryException if an error occurs. + * @throws RepositoryException if an error occurs * * @api */ - abstract protected function entering(ItemInterface $item, $depth); + abstract protected function entering(ItemInterface $item, int $depth): void; /** * Implement this method to add behavior performed after a Property is * visited. * * @param ItemInterface $item the Item that is accepting this - * visitor. + * visitor * @param int $depth hierarchy level of this property (the root node - * starts at depth 0). + * starts at depth 0) * - * @throws RepositoryException if an error occurs. + * @throws RepositoryException if an error occurs * * @api */ - abstract protected function leaving(ItemInterface $item, $depth); + abstract protected function leaving(ItemInterface $item, int $depth): void; /** * Called when the Visitor is passed to an Item. @@ -144,15 +129,15 @@ abstract protected function leaving(ItemInterface $item, $depth); * If this method throws, the visiting process is aborted. * * @param ItemInterface $item the Node or Property that is accepting - * this visitor. + * this visitor * - * @throws RepositoryException if an error occurs. + * @throws RepositoryException if an error occurs * * @api */ - public function visit(ItemInterface $item) + public function visit(ItemInterface $item): void { - if ($this->currentDepth === 0) { + if (0 === $this->currentDepth) { $this->currentDepth = $item->getDepth(); } if ($item instanceof PropertyInterface) { @@ -164,15 +149,15 @@ public function visit(ItemInterface $item) 'Internal error in TraversingItemVisitor: item %s at %s is not a node but %s', $item->getName(), $item->getPath(), - get_class($item) + $item::class )); } try { - if ($this->breadthFirst === false) { + if (false === $this->breadthFirst) { $this->entering($item, $this->currentDepth); - if ($this->maxDepth === -1 || $this->currentDepth < $this->maxDepth) { - $this->currentDepth++; + if (-1 === $this->maxDepth || $this->currentDepth < $this->maxDepth) { + ++$this->currentDepth; foreach ($item->getProperties() as $property) { /* @var $property PropertyInterface */ $property->accept($this); @@ -181,14 +166,14 @@ public function visit(ItemInterface $item) /* @var $node NodeInterface */ $node->accept($this); } - $this->currentDepth--; + --$this->currentDepth; } $this->leaving($item, $this->currentDepth); } else { $this->entering($item, $this->currentDepth); $this->leaving($item, $this->currentDepth); - if ($this->maxDepth === -1 || $this->currentDepth < $this->maxDepth) { + if (-1 === $this->maxDepth || $this->currentDepth < $this->maxDepth) { foreach ($item->getProperties() as $property) { /* @var $property PropertyInterface */ $property->accept($this); @@ -201,9 +186,9 @@ public function visit(ItemInterface $item) while (!$this->currentQueue->isEmpty() || !$this->nextQueue->isEmpty()) { if ($this->currentQueue->isEmpty()) { - $this->currentDepth++; + ++$this->currentDepth; $this->currentQueue = $this->nextQueue; - $this->nextQueue = new SplQueue(); + $this->nextQueue = new \SplQueue(); } $item = $this->currentQueue->dequeue(); $item->accept($this); diff --git a/src/PHPCR/Util/TreeWalker.php b/src/PHPCR/Util/TreeWalker.php index 2eaf6e3c..0588c94d 100644 --- a/src/PHPCR/Util/TreeWalker.php +++ b/src/PHPCR/Util/TreeWalker.php @@ -1,5 +1,7 @@ nodeVisitor = $nodeVisitor; $this->propertyVisitor = $propertyVisitor; } - /** - * Add a filter to select the nodes that will be traversed. - * - * @param TreeWalkerFilterInterface $filter - */ - public function addNodeFilter(TreeWalkerFilterInterface $filter) + public function addNodeFilter(TreeWalkerFilterInterface $filter): void { - if (!in_array($filter, $this->nodeFilters)) { + if (!in_array($filter, $this->nodeFilters, true)) { $this->nodeFilters[] = $filter; } } - /** - * Add a filter to select the properties that will be traversed. - * - * @param TreeWalkerFilterInterface $filter - */ - public function addPropertyFilter(TreeWalkerFilterInterface $filter) + public function addPropertyFilter(TreeWalkerFilterInterface $filter): void { - if (!in_array($filter, $this->propertyFilters)) { + if (!in_array($filter, $this->propertyFilters, true)) { $this->propertyFilters[] = $filter; } } /** * Return whether a node must be traversed or not. - * - * @param NodeInterface $node - * - * @return bool */ - protected function mustVisitNode(NodeInterface $node) + protected function mustVisitNode(NodeInterface $node): bool { foreach ($this->nodeFilters as $filter) { if (!$filter->mustVisit($node)) { @@ -99,12 +75,8 @@ protected function mustVisitNode(NodeInterface $node) /** * Return whether a node property must be traversed or not. - * - * @param PropertyInterface $property - * - * @return bool */ - protected function mustVisitProperty(PropertyInterface $property) + protected function mustVisitProperty(PropertyInterface $property): bool { foreach ($this->propertyFilters as $filter) { if (!$filter->mustVisit($property)) { @@ -116,13 +88,10 @@ protected function mustVisitProperty(PropertyInterface $property) } /** - * Traverse a node. - * - * @param NodeInterface $node - * @param int $recurse Max recursion level - * @param int $level Recursion level + * @param int $recurse Max recursion level + * @param int $level Current recursion level */ - public function traverse(NodeInterface $node, $recurse = -1, $level = 0): void + public function traverse(NodeInterface $node, int $recurse = -1, int $level = 0): void { if ($this->mustVisitNode($node)) { // Visit node @@ -135,7 +104,7 @@ public function traverse(NodeInterface $node, $recurse = -1, $level = 0): void $node->accept($this->nodeVisitor); // Visit properties - if ($this->propertyVisitor !== null) { + if (null !== $this->propertyVisitor) { foreach ($node->getProperties() as $prop) { if ($this->mustVisitProperty($prop)) { if (method_exists($this->propertyVisitor, 'setLevel')) { diff --git a/src/PHPCR/Util/TreeWalkerFilterInterface.php b/src/PHPCR/Util/TreeWalkerFilterInterface.php index 41272d79..e967c932 100644 --- a/src/PHPCR/Util/TreeWalkerFilterInterface.php +++ b/src/PHPCR/Util/TreeWalkerFilterInterface.php @@ -1,5 +1,7 @@ toString(); + return Uuid::uuid4()->toString(); } return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', // 32 bits for "time_low" - mt_rand(0, 0xFFFF), - mt_rand(0, 0xFFFF), + random_int(0, 0xFFFF), + random_int(0, 0xFFFF), // 16 bits for "time_mid" - mt_rand(0, 0xFFFF), + random_int(0, 0xFFFF), // 16 bits for "time_hi_and_version", // four most significant bits holds version number 4 - mt_rand(0, 0x0FFF) | 0x4000, + random_int(0, 0x0FFF) | 0x4000, // 16 bits, 8 bits for "clk_seq_hi_res", // 8 bits for "clk_seq_low", // two most significant bits holds zero and one for variant DCE1.1 - mt_rand(0, 0x3FFF) | 0x8000, + random_int(0, 0x3FFF) | 0x8000, // 48 bits for "node" - mt_rand(0, 0xFFFF), - mt_rand(0, 0xFFFF), - mt_rand(0, 0xFFFF) + random_int(0, 0xFFFF), + random_int(0, 0xFFFF), + random_int(0, 0xFFFF) ); } } diff --git a/src/PHPCR/Util/ValueConverter.php b/src/PHPCR/Util/ValueConverter.php index 859cdfec..8b1bc2a4 100644 --- a/src/PHPCR/Util/ValueConverter.php +++ b/src/PHPCR/Util/ValueConverter.php @@ -1,10 +1,11 @@ isNodeType('mix:referenceable')) { throw new ValueFormatException('Node '.$value->getPath().' is not referenceable'); } @@ -154,9 +154,10 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) case PropertyType::STRING: switch ($srcType) { case PropertyType::DATE: - if (!$value instanceof DateTime) { + if (!$value instanceof \DateTime) { throw new RepositoryException('Cannot convert a date that is not a \DateTime instance to string'); } + /* @var $value DateTime */ // Milliseconds formatting is not possible in PHP so we // construct it by cutting microseconds to 3 positions. @@ -170,15 +171,17 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) return $value; default: if (is_object($value)) { - throw new ValueFormatException('Cannot convert object of class "'.get_class($value).'" to STRING'); + throw new ValueFormatException('Cannot convert object of class "'.$value::class.'" to STRING'); } if (is_resource($value)) { throw new ValueFormatException('Inconsistency: Non-binary property should not have resource stream value'); } + // TODO: how can we provide ValueFormatException on failure? invalid casting leads to 'catchable fatal error' instead of exception return (string) $value; } + // no break case PropertyType::BINARY: if (is_resource($value)) { return $value; @@ -201,7 +204,7 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) case PropertyType::DECIMAL: return (int) $value; case PropertyType::DATE: - if (!$value instanceof DateTime) { + if (!$value instanceof \DateTime) { throw new RepositoryException('something weird'); } /* @var $value DateTime */ @@ -209,7 +212,7 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) return $value->getTimestamp(); } if (is_object($value)) { - throw new ValueFormatException('Cannot convert object of class "'.get_class($value).'" to a LONG'); + throw new ValueFormatException('Cannot convert object of class "'.$value::class.'" to a LONG'); } throw new ValueFormatException('Cannot convert "'.var_export($value, true).'" to a LONG'); @@ -222,7 +225,7 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) case PropertyType::DECIMAL: return (float) $value; case PropertyType::DATE: - if (!$value instanceof DateTime) { + if (!$value instanceof \DateTime) { throw new RepositoryException('something weird'); } @@ -231,7 +234,7 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) return (float) $value->getTimestamp(); } if (is_object($value)) { - throw new ValueFormatException('Cannot convert object of class "'.get_class($value).'" to a DOUBLE'); + throw new ValueFormatException('Cannot convert object of class "'.$value::class.'" to a DOUBLE'); } throw new ValueFormatException('Cannot convert "'.var_export($value, true).'" to a DOUBLE'); @@ -239,25 +242,36 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) switch ($srcType) { case PropertyType::STRING: case PropertyType::DATE: - if ($value instanceof DateTime) { + if ($value instanceof \DateTime) { return $value; } try { - return new DateTime($value); - } catch (Exception $e) { + return new \DateTime($value); + } catch (\Exception $e) { throw new ValueFormatException("String '$value' is not a valid date", 0, $e); } case PropertyType::LONG: + return (new \DateTime()) + ->setTimestamp($value) + ; case PropertyType::DOUBLE: + return (new \DateTime()) + ->setTimestamp((int) round($value)) + ; case PropertyType::DECIMAL: - $datetime = new DateTime(); - $datetime = $datetime->setTimestamp(round($value)); + if (function_exists('bccomp') + && 1 === \bccomp($value, (string) PHP_INT_MAX) + ) { + throw new ValueFormatException('Decimal number is too large for integer'); + } - return $datetime; + return (new \DateTime()) + ->setTimestamp((int) round((float) $value)) + ; } if (is_object($value)) { - throw new ValueFormatException('Cannot convert object of class "'.get_class($value).'" to a DATE'); + throw new ValueFormatException('Cannot convert object of class "'.$value::class.'" to a DATE'); } throw new ValueFormatException('Cannot convert "'.var_export($value, true).'" to DATE'); @@ -276,7 +290,7 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) return (bool) ((float) $value); // '0' is false too } if (is_object($value)) { - throw new ValueFormatException('Cannot convert object of class "'.get_class($value).'" to a BOOLEAN'); + throw new ValueFormatException('Cannot convert object of class "'.$value::class.'" to a BOOLEAN'); } throw new ValueFormatException('Cannot convert "'.var_export($value, true).'" to a BOOLEAN'); @@ -292,7 +306,7 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) return $value; } if (is_object($value)) { - throw new ValueFormatException('Cannot convert object of class "'.get_class($value).'" to a NAME'); + throw new ValueFormatException('Cannot convert object of class "'.$value::class.'" to a NAME'); } throw new ValueFormatException('Cannot convert "'.var_export($value, true).'" to NAME'); @@ -309,7 +323,7 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) return $value; } if (is_object($value)) { - throw new ValueFormatException('Cannot convert object of class "'.get_class($value).'" to a PATH'); + throw new ValueFormatException('Cannot convert object of class "'.$value::class.'" to a PATH'); } throw new ValueFormatException('Cannot convert "'.var_export($value, true).'" to PATH'); @@ -320,14 +334,14 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) case PropertyType::REFERENCE: case PropertyType::WEAKREFERENCE: if (empty($value)) { - //TODO check if string is valid uuid + // TODO check if string is valid uuid throw new ValueFormatException('Value "'.var_export($value, true).'" is not a valid unique id'); } return $value; } if (is_object($value)) { - throw new ValueFormatException('Cannot convert object of class "'.get_class($value).'" to a unique id'); + throw new ValueFormatException('Cannot convert object of class "'.$value::class.'" to a unique id'); } throw new ValueFormatException('Cannot convert "'.var_export($value, true).'" to unique id'); @@ -339,9 +353,9 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) case PropertyType::NAME: return '../'.rawurlencode($value); case PropertyType::PATH: - if (strlen($value) > 0 - && '/' != $value[0] - && '.' != $value[0] + if ('' !== $value + && '/' !== $value[0] + && '.' !== $value[0] ) { $value = './'.$value; } @@ -351,7 +365,7 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) return $value; } if (is_object($value)) { - throw new ValueFormatException('Cannot convert object of class "'.get_class($value).'" to a URI'); + throw new ValueFormatException('Cannot convert object of class "'.$value::class.'" to a URI'); } throw new ValueFormatException('Cannot convert "'.var_export($value, true).'" to URI'); @@ -371,7 +385,7 @@ public function convertType($value, $type, $srcType = PropertyType::UNDEFINED) return (string) $value->getTimestamp(); } if (is_object($value)) { - throw new ValueFormatException('Cannot convert object of class "'.get_class($value).'" to a DECIMAL'); + throw new ValueFormatException('Cannot convert object of class "'.$value::class.'" to a DECIMAL'); } throw new ValueFormatException('Cannot convert "'.var_export($value, true).'" to a DECIMAL'); diff --git a/tests/PHPCR/Tests/Stubs/MockNode.php b/tests/PHPCR/Tests/Stubs/MockNode.php index e0249394..5d27eac6 100644 --- a/tests/PHPCR/Tests/Stubs/MockNode.php +++ b/tests/PHPCR/Tests/Stubs/MockNode.php @@ -1,10 +1,14 @@ + */ +abstract class MockNode implements \Iterator, NodeInterface { } diff --git a/tests/PHPCR/Tests/Stubs/MockNodeTypeManager.php b/tests/PHPCR/Tests/Stubs/MockNodeTypeManager.php index 7cd46605..f3fe1df2 100644 --- a/tests/PHPCR/Tests/Stubs/MockNodeTypeManager.php +++ b/tests/PHPCR/Tests/Stubs/MockNodeTypeManager.php @@ -1,10 +1,15 @@ + */ +abstract class MockNodeTypeManager implements \Iterator, NodeTypeManagerInterface { } diff --git a/tests/PHPCR/Tests/Stubs/MockRow.php b/tests/PHPCR/Tests/Stubs/MockRow.php index 45077223..95112378 100644 --- a/tests/PHPCR/Tests/Stubs/MockRow.php +++ b/tests/PHPCR/Tests/Stubs/MockRow.php @@ -1,10 +1,14 @@ + */ +abstract class MockRow implements \Iterator, RowInterface { } diff --git a/tests/PHPCR/Tests/Util/CND/Reader/BufferReaderTest.php b/tests/PHPCR/Tests/Util/CND/Reader/BufferReaderTest.php index 86fd7479..2e4dc33e 100644 --- a/tests/PHPCR/Tests/Util/CND/Reader/BufferReaderTest.php +++ b/tests/PHPCR/Tests/Util/CND/Reader/BufferReaderTest.php @@ -1,5 +1,7 @@ assertEquals($reader->getEofMarker(), $reader->forward()); } - public function test__constructEmptyString() + public function testConstructEmptyString(): void { $reader = new BufferReader(''); diff --git a/tests/PHPCR/Tests/Util/CND/Reader/FileReaderTest.php b/tests/PHPCR/Tests/Util/CND/Reader/FileReaderTest.php index 5d3d1a2d..1e49cbb4 100644 --- a/tests/PHPCR/Tests/Util/CND/Reader/FileReaderTest.php +++ b/tests/PHPCR/Tests/Util/CND/Reader/FileReaderTest.php @@ -1,8 +1,9 @@ expectException(InvalidArgumentException::class); + $this->expectException(\InvalidArgumentException::class); new FileReader('unexisting_file'); } - public function testGetPath() + public function testGetPath(): void { $this->assertEquals($this->filepath, $this->reader->getPath()); } - public function testGetNextChar() + public function testGetNextChar(): void { $curLine = 1; $curCol = 1; - for ($i = 0; $i < count($this->chars); $i++) { + for ($i = 0; $i < count($this->chars); ++$i) { $peek = $this->reader->currentChar(); if ($peek === $this->reader->getEofMarker()) { @@ -80,11 +81,11 @@ public function testGetNextChar() $this->assertFalse($this->reader->isEof()); // Assert isEol is true at end of the lines - if ($peek === "\n") { - $curLine++; + if ("\n" === $peek) { + ++$curLine; $curCol = 1; } else { - $curCol++; + ++$curCol; } // Assert the next character is the expected one diff --git a/tests/PHPCR/Tests/Util/CND/Scanner/GenericScannerTest.php b/tests/PHPCR/Tests/Util/CND/Scanner/GenericScannerTest.php index 59f9377d..7021b05f 100644 --- a/tests/PHPCR/Tests/Util/CND/Scanner/GenericScannerTest.php +++ b/tests/PHPCR/Tests/Util/CND/Scanner/GenericScannerTest.php @@ -1,8 +1,9 @@ + */ + private array $expectedTokens = [ // [Token::TK_SYMBOL, '<'], [Token::TK_SYMBOL, '?'], @@ -104,19 +107,22 @@ class GenericScannerTest extends TestCase [Token::TK_NEWLINE, ''], ]; - protected $expectedTokensNoEmptyToken; + /** + * @var array + */ + protected array $expectedTokensNoEmptyToken; public function setUp(): void { $this->expectedTokensNoEmptyToken = []; foreach ($this->expectedTokens as $token) { - if ($token[0] !== Token::TK_NEWLINE && $token[0] !== Token::TK_WHITESPACE) { + if (Token::TK_NEWLINE !== $token[0] && Token::TK_WHITESPACE !== $token[0]) { $this->expectedTokensNoEmptyToken[] = $token; } } } - public function testScan() + public function testScan(): void { $reader = new FileReader(__DIR__.'/../Fixtures/files/TestFile.php'); @@ -126,7 +132,7 @@ public function testScan() $this->assertTokens($this->expectedTokens, $queue); } - public function testFilteredScan() + public function testFilteredScan(): void { $reader = new FileReader(__DIR__.'/../Fixtures/files/TestFile.php'); @@ -140,15 +146,20 @@ public function testFilteredScan() $this->assertTokens($this->expectedTokensNoEmptyToken, $queue); } - protected function assertTokens($tokens, TokenQueue $queue) + /** + * @param array $tokens + */ + protected function assertTokens(array $tokens, TokenQueue $queue): void { $queue->reset(); - $it = new ArrayIterator($tokens); + $it = new \ArrayIterator($tokens); $token = $queue->peek(); while ($it->valid()) { + $this->assertInstanceOf(Token::class, $token); + $expectedToken = $it->current(); $this->assertFalse($queue->isEof(), 'There is no more tokens, expected = '.$expectedToken[1]); @@ -162,7 +173,7 @@ protected function assertTokens($tokens, TokenQueue $queue) $this->assertTrue($queue->isEof(), 'There are more unexpected tokens.'); } - protected function assertToken($type, $data, Token $token) + protected function assertToken(int $type, string $data, Token $token): void { $this->assertEquals( $type, diff --git a/tests/PHPCR/Tests/Util/CND/Scanner/TokenQueueTest.php b/tests/PHPCR/Tests/Util/CND/Scanner/TokenQueueTest.php index 7af6afb0..8b653c50 100644 --- a/tests/PHPCR/Tests/Util/CND/Scanner/TokenQueueTest.php +++ b/tests/PHPCR/Tests/Util/CND/Scanner/TokenQueueTest.php @@ -1,5 +1,7 @@ queue->add($this->token3); } - public function testAdd() + public function testAdd(): void { $queue = new TokenQueue(); $reflection = new \ReflectionClass($queue); @@ -62,13 +64,13 @@ public function testAdd() $this->assertSame([$this->token0, $this->token1], $tokens->getValue($queue)); } - public function testResetAndPeek() + public function testResetAndPeek(): void { $this->assertEquals($this->token0, $this->queue->reset()); $this->assertEquals($this->token0, $this->queue->peek()); } - public function testIsEofAndNext() + public function testIsEofAndNext(): void { // Token0 $this->assertFalse($this->queue->isEof()); @@ -90,7 +92,7 @@ public function testIsEofAndNext() $this->assertTrue($this->queue->isEof()); } - public function testIsEofEmptyQueue() + public function testIsEofEmptyQueue(): void { $queue = new TokenQueue(); $this->assertTrue($queue->isEof()); @@ -98,7 +100,7 @@ public function testIsEofEmptyQueue() $this->assertFalse($queue->isEof()); } - public function testGet() + public function testGet(): void { $this->queue->reset(); $this->assertEquals($this->token0, $this->queue->get()); @@ -108,7 +110,7 @@ public function testGet() $this->assertEquals(false, $this->queue->get()); } - public function testGetIterator() + public function testGetIterator(): void { $this->assertEquals( [$this->token0, $this->token1, $this->token2, $this->token3], diff --git a/tests/PHPCR/Tests/Util/CND/Scanner/TokenTest.php b/tests/PHPCR/Tests/Util/CND/Scanner/TokenTest.php index 8f81190b..79cf6603 100644 --- a/tests/PHPCR/Tests/Util/CND/Scanner/TokenTest.php +++ b/tests/PHPCR/Tests/Util/CND/Scanner/TokenTest.php @@ -1,5 +1,7 @@ token = new Token(123, 'foobar'); } - public function test__construct() + public function testConstruct(): void { - $this->assertSame(123, $this->token->type); - $this->assertSame('foobar', $this->token->data); + $this->assertSame(123, $this->token->getType()); + $this->assertSame('foobar', $this->token->getData()); } - public function testGetData() + public function testGetData(): void { $this->assertEquals('foobar', $this->token->getData()); } - public function testGetType() + public function testGetType(): void { $this->assertEquals(123, $this->token->getType()); } - public function test__toString() + public function testToString(): void { $this->assertEquals('TOKEN(123, \'foobar\', 0, 0)', $this->token->__toString()); } diff --git a/tests/PHPCR/Tests/Util/Console/Command/BaseCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/BaseCommandTest.php index f935b7df..a0300cec 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/BaseCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/BaseCommandTest.php @@ -1,5 +1,7 @@ getMock(); $this->helperSet = new HelperSet([ - 'phpcr' => new PhpcrHelper($this->session), + 'phpcr' => new PhpcrHelper($this->session), 'phpcr_console_dumper' => $this->dumperHelper, ]); @@ -111,18 +113,14 @@ public function setUp(): void /** * Build and execute the command tester. * - * @param string $name command name - * @param array $args command arguments - * @param int $status expected return status - * - * @return CommandTester + * @param mixed[] $arguments */ - public function executeCommand($name, $args, $status = 0) + public function executeCommand(string $commandName, array $arguments, int $expectedReturnStatus = 0): CommandTester { - $command = $this->application->find($name); + $command = $this->application->find($commandName); $commandTester = new CommandTester($command); - $args = array_merge(['command' => $command->getName()], $args); - $this->assertEquals($status, $commandTester->execute($args)); + $arguments = array_merge(['command' => $command->getName()], $arguments); + $this->assertEquals($expectedReturnStatus, $commandTester->execute($arguments)); return $commandTester; } diff --git a/tests/PHPCR/Tests/Util/Console/Command/NodeDumpCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/NodeDumpCommandTest.php index 993d4864..5e5da9a9 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/NodeDumpCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/NodeDumpCommandTest.php @@ -1,8 +1,9 @@ application->add($ndCommand); } - public function testCommand() + public function testCommand(): void { $this->dumperHelper ->expects($this->once()) @@ -46,7 +47,7 @@ public function testCommand() $this->executeCommand('phpcr:node:dump', []); } - public function testCommandIdentifier() + public function testCommandIdentifier(): void { $uuid = UUIDHelper::generateUUID(); @@ -69,15 +70,15 @@ public function testCommandIdentifier() $this->executeCommand('phpcr:node:dump', ['identifier' => $uuid]); } - public function testInvalidRefFormat() + public function testInvalidRefFormat(): void { - $this->expectException(Exception::class); + $this->expectException(\Exception::class); $this->executeCommand('phpcr:node:dump', ['--ref-format' => 'xy']); $this->fail('invalid ref-format did not produce exception'); } - public function testNotFound() + public function testNotFound(): void { $this->session ->expects($this->once()) diff --git a/tests/PHPCR/Tests/Util/Console/Command/NodeMoveCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/NodeMoveCommandTest.php index 132aafb7..4dee112a 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/NodeMoveCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/NodeMoveCommandTest.php @@ -1,20 +1,34 @@ > + */ + public function provideCommand(): array { - return [[['source' => '/foo', 'destination' => '/bar']]]; + return [ + [ + [ + 'source' => '/foo', + 'destination' => '/bar', + ], + ], + ]; } /** * @dataProvider provideCommand + * + * @param array $args */ - public function testCommand($args) + public function testCommand(array $args): void { $this->session->expects($this->once()) ->method('move') diff --git a/tests/PHPCR/Tests/Util/Console/Command/NodeRemoveCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/NodeRemoveCommandTest.php index c103ee42..6381ba59 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/NodeRemoveCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/NodeRemoveCommandTest.php @@ -1,8 +1,9 @@ application->add(new NodeRemoveCommand()); } - public function testRemove() + public function testRemove(): void { $this->session->expects($this->once()) ->method('removeItem') @@ -22,17 +23,17 @@ public function testRemove() $this->executeCommand('phpcr:node:remove', [ '--force' => true, - 'path' => '/cms', + 'path' => '/cms', ]); } - public function testRemoveRoot() + public function testRemoveRoot(): void { - $this->expectException(LogicException::class); + $this->expectException(\LogicException::class); $this->executeCommand('phpcr:node:remove', [ '--force' => true, - 'path' => '/', + 'path' => '/', ]); } } diff --git a/tests/PHPCR/Tests/Util/Console/Command/NodeTouchCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/NodeTouchCommandTest.php index 0bbb59ac..afc746d3 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/NodeTouchCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/NodeTouchCommandTest.php @@ -1,8 +1,9 @@ helperSet->set($this->phpcrHelper); } - public function testTouch() + public function testTouch(): void { $node = $this->node1; $child = $this->createMock(MockNode::class); @@ -58,7 +59,7 @@ public function testTouch() throw new PathNotFoundException(); } - throw new Exception('Unexpected '.$path); + throw new \Exception('Unexpected '.$path); }); $this->node1->expects($this->once()) @@ -72,7 +73,7 @@ public function testTouch() $this->executeCommand('phpcr:node:touch', ['path' => '/cms']); } - public function testUpdate() + public function testUpdate(): void { $nodeType = $this->createMock(NodeTypeInterface::class); $nodeType->expects($this->once()) @@ -92,7 +93,7 @@ public function testUpdate() $this->phpcrHelper->expects($this->once()) ->method('processNode') - ->willReturnCallback(function ($output, $node, $options) use ($me) { + ->willReturnCallback(function ($output, $node, $options) use ($me): void { $me->assertEquals($me->node1, $node); $me->assertEquals([ 'setProp' => ['foo=bar'], @@ -104,12 +105,12 @@ public function testUpdate() }); $this->executeCommand('phpcr:node:touch', [ - 'path' => '/cms', - '--set-prop' => ['foo=bar'], - '--remove-prop' => ['bar'], - '--add-mixin' => ['foo:bar'], + 'path' => '/cms', + '--set-prop' => ['foo=bar'], + '--remove-prop' => ['bar'], + '--add-mixin' => ['foo:bar'], '--remove-mixin' => ['bar:foo'], - '--dump' => true, + '--dump' => true, ]); } } diff --git a/tests/PHPCR/Tests/Util/Console/Command/NodeTypeListCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/NodeTypeListCommandTest.php index f74f6fde..fb25baf0 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/NodeTypeListCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/NodeTypeListCommandTest.php @@ -1,5 +1,7 @@ getMock(); } - public function testNodeTypeList() + public function testNodeTypeList(): void { $this->session->expects($this->once()) ->method('getWorkspace') diff --git a/tests/PHPCR/Tests/Util/Console/Command/NodeTypeRegisterCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/NodeTypeRegisterCommandTest.php index b39fe38a..712b4a13 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/NodeTypeRegisterCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/NodeTypeRegisterCommandTest.php @@ -1,5 +1,7 @@ getMock(); } - public function testNodeTypeRegister() + public function testNodeTypeRegister(): void { $this->session->expects($this->once()) ->method('getWorkspace') diff --git a/tests/PHPCR/Tests/Util/Console/Command/NodesUpdateCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/NodesUpdateCommandTest.php index 542fe109..6806109e 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/NodesUpdateCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/NodesUpdateCommandTest.php @@ -1,8 +1,9 @@ query = $this->createMock(QueryInterface::class); } - public function provideNodeUpdate() + /** + * @return array>> + */ + public function provideNodeUpdate(): array { return [ // No query specified - [['exception' => InvalidArgumentException::class]], + [[ + 'exception' => \InvalidArgumentException::class, + ]], // Specify query - [['query' => 'SELECT * FROM nt:unstructured WHERE foo="bar"']], + [[ + 'query' => 'SELECT * FROM nt:unstructured WHERE foo="bar"', + ]], // Set, remote properties and mixins [[ - 'setProp' => [['foo', 'bar']], - 'removeProp' => ['bar'], - 'addMixin' => ['mixin1'], + 'setProp' => [['foo', 'bar']], + 'removeProp' => ['bar'], + 'addMixin' => ['mixin1'], 'removeMixin' => ['mixin1'], - 'query' => 'SELECT * FROM nt:unstructured', + 'query' => 'SELECT * FROM nt:unstructured', ]], ]; } - protected function setupQueryManager($options) + /** + * @param array $options + */ + protected function setupQueryManager(array $options): void { $options = array_merge(['query' => ''], $options); @@ -68,16 +79,18 @@ protected function setupQueryManager($options) /** * @dataProvider provideNodeUpdate + * + * @param array $options */ - public function testNodeUpdate($options) + public function testNodeUpdate(array $options): void { $options = array_merge([ - 'query' => null, - 'setProp' => [], - 'removeProp' => [], - 'addMixin' => [], + 'query' => null, + 'setProp' => [], + 'removeProp' => [], + 'addMixin' => [], 'removeMixin' => [], - 'exception' => null, + 'exception' => null, ], $options); if ($options['exception']) { @@ -87,17 +100,17 @@ public function testNodeUpdate($options) $this->setupQueryManager($options); $args = [ - '--query' => $options['query'], + '--query' => $options['query'], '--no-interaction' => true, - '--set-prop' => [], - '--remove-prop' => [], - '--add-mixin' => [], - '--remove-mixin' => [], + '--set-prop' => [], + '--remove-prop' => [], + '--add-mixin' => [], + '--remove-mixin' => [], ]; $setPropertyArguments = []; foreach ($options['setProp'] as $setProp) { - list($prop, $value) = $setProp; + [$prop, $value] = $setProp; $setPropertyArguments[] = [$prop, $value, null]; $args['--set-prop'][] = $prop.'='.$value; } @@ -130,14 +143,14 @@ public function testNodeUpdate($options) $this->executeCommand('phpcr:nodes:update', $args); } - public function testApplyClosure() + public function testApplyClosure(): void { $args = [ - '--query' => 'SELECT foo FROM bar', + '--query' => 'SELECT foo FROM bar', '--no-interaction' => true, - '--apply-closure' => [ + '--apply-closure' => [ '$session->getNodeByIdentifier("/foo"); $node->setProperty("foo", "bar");', - function ($session, $node) { + function ($session, $node): void { $node->setProperty('foo', 'bar'); }, ], diff --git a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceCreateCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceCreateCommandTest.php index 7df686b8..f3352a3b 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceCreateCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceCreateCommandTest.php @@ -1,5 +1,7 @@ application->add(new WorkspaceCreateCommand()); } - public function testCreate() + public function testCreate(): void { $this->session->expects($this->once()) ->method('getWorkspace') @@ -45,7 +47,7 @@ public function testCreate() /** * Handle trying to create existing workspace. */ - public function testCreateExisting() + public function testCreateExisting(): void { $this->session->expects($this->exactly(2)) ->method('getWorkspace') @@ -75,7 +77,7 @@ public function testCreateExisting() $tester = $this->executeCommand( 'phpcr:workspace:create', [ - 'name' => 'test', + 'name' => 'test', '--ignore-existing' => true, ], 0 diff --git a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceDeleteCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceDeleteCommandTest.php index 9808db4b..30df1404 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceDeleteCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceDeleteCommandTest.php @@ -1,5 +1,7 @@ application->add(new WorkspaceDeleteCommand()); } - public function testDelete() + public function testDelete(): void { $this->session->expects($this->once()) ->method('getWorkspace') @@ -38,14 +40,14 @@ public function testDelete() ->with('test_workspace'); $ct = $this->executeCommand('phpcr:workspace:delete', [ - 'name' => 'test_workspace', + 'name' => 'test_workspace', '--force' => 'true', ]); $this->assertStringContainsString("Deleted workspace 'test_workspace'.", $ct->getDisplay()); } - public function testDeleteNonexistent() + public function testDeleteNonexistent(): void { $this->session->expects($this->once()) ->method('getWorkspace') @@ -56,7 +58,7 @@ public function testDeleteNonexistent() ->willReturn(['default', 'other']); $ct = $this->executeCommand('phpcr:workspace:delete', [ - 'name' => 'test_workspace', + 'name' => 'test_workspace', '--force' => 'true', ]); diff --git a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceExportCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceExportCommandTest.php index a16e2656..1868ed0c 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceExportCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceExportCommandTest.php @@ -1,5 +1,7 @@ session->expects($this->once()) ->method('getRepository') diff --git a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceImportCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceImportCommandTest.php index d2b5ebd9..13e16cf4 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceImportCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceImportCommandTest.php @@ -1,5 +1,7 @@ application->add(new WorkspaceImportCommand()); } - public function testImport() + public function testImport(): void { $this->session->expects($this->once()) ->method('getRepository') @@ -37,7 +39,7 @@ public function testImport() $this->assertStringContainsString('Successfully imported', $ct->getDisplay()); } - public function testImportUuidBehaviorThrow() + public function testImportUuidBehaviorThrow(): void { $this->session->expects($this->once()) ->method('getRepository') @@ -53,7 +55,7 @@ public function testImportUuidBehaviorThrow() ->with('/', 'test_import.xml', ImportUUIDBehaviorInterface::IMPORT_UUID_COLLISION_THROW); $ct = $this->executeCommand('phpcr:workspace:import', [ - 'filename' => 'test_import.xml', + 'filename' => 'test_import.xml', '--uuid-behavior' => 'throw', ]); diff --git a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceListCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceListCommandTest.php index 86ef8fc7..1044200d 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceListCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceListCommandTest.php @@ -1,5 +1,7 @@ application->add(new WorkspaceListCommand()); } - public function testNodeTypeList() + public function testNodeTypeList(): void { $this->session->expects($this->once()) ->method('getWorkspace') @@ -27,11 +29,11 @@ public function testNodeTypeList() ]); $expected = <<<'HERE' -The following 2 workspaces are available: -foo -bar + The following 2 workspaces are available: + foo + bar -HERE; + HERE; $this->assertEquals($expected, $ct->getDisplay()); } diff --git a/tests/PHPCR/Tests/Util/Console/Command/WorkspacePurgeCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/WorkspacePurgeCommandTest.php index 5938ac86..f37ecfe1 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/WorkspacePurgeCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/WorkspacePurgeCommandTest.php @@ -1,5 +1,7 @@ application->add(new WorkspacePurgeCommand()); } - public function testNodeTypePurge() + public function testNodeTypePurge(): void { $this->session->expects($this->once()) ->method('getRootNode') diff --git a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceQueryCommandTest.php b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceQueryCommandTest.php index 9ab438bb..d7510126 100644 --- a/tests/PHPCR/Tests/Util/Console/Command/WorkspaceQueryCommandTest.php +++ b/tests/PHPCR/Tests/Util/Console/Command/WorkspaceQueryCommandTest.php @@ -1,5 +1,7 @@ query = $this->createMock(QueryInterface::class); } - public function testQuery() + public function testQuery(): void { $this->queryManager ->method('getSupportedQueryLanguages') diff --git a/tests/PHPCR/Tests/Util/Console/Helper/PhpcrConsoleDumperHelperTest.php b/tests/PHPCR/Tests/Util/Console/Helper/PhpcrConsoleDumperHelperTest.php index 057b3a6e..748fb872 100644 --- a/tests/PHPCR/Tests/Util/Console/Helper/PhpcrConsoleDumperHelperTest.php +++ b/tests/PHPCR/Tests/Util/Console/Helper/PhpcrConsoleDumperHelperTest.php @@ -1,13 +1,20 @@ helper = new PhpcrConsoleDumperHelper(); } - public function provideHelper() + /** + * @return array>> + */ + public function provideHelper(): array { - return [[[]], [['show_props' => true]]]; + return [ + [[]], + [['show_props' => true]], + ]; } /** * @dataProvider provideHelper + * + * @param array $options */ - public function testGetTreeWalker($options) + public function testGetTreeWalker(array $options): void { $options = array_merge([ - 'dump_uuids' => false, - 'ref_format' => 'uuid', - 'show_props' => false, + 'dump_uuids' => false, + 'ref_format' => 'uuid', + 'show_props' => false, 'show_sys_nodes' => false, ], $options); $tw = $this->helper->getTreeWalker($this->outputMock, $options); - $this->assertInstanceOf(TreeWalker::class, $tw); - $reflection = new ReflectionClass($tw); + $reflection = new \ReflectionClass($tw); $propVisitorProp = $reflection->getProperty('propertyVisitor'); $propVisitorProp->setAccessible(true); $propVisitor = $propVisitorProp->getValue($tw); - if ($options['show_props'] === true) { + if (true === $options['show_props']) { $this->assertInstanceOf(ConsoleDumperPropertyVisitor::class, $propVisitor); } else { $this->assertNull($propVisitor); diff --git a/tests/PHPCR/Tests/Util/NodeHelperTest.php b/tests/PHPCR/Tests/Util/NodeHelperTest.php index bebad5e2..1878745e 100644 --- a/tests/PHPCR/Tests/Util/NodeHelperTest.php +++ b/tests/PHPCR/Tests/Util/NodeHelperTest.php @@ -1,11 +1,12 @@ */ - private $namespaces = ['a' => 'http://phpcr/', 'b' => 'http://jcr/']; + private array $namespaces = ['a' => 'http://phpcr/', 'b' => 'http://jcr/']; /** - * @var array + * @var string[] */ - private $usedNames = ['a:x', 'b:y', 'c']; + private array $usedNames = ['a:x', 'b:y', 'c']; /** - * @return array + * @return array */ - public static function hints() + public static function hints(): array { return [ ['', true], @@ -39,9 +40,9 @@ public static function hints() } /** - * @return array + * @return array> */ - public static function invalidHints() + public static function invalidHints(): array { return [ ['::'], @@ -55,7 +56,7 @@ public static function invalidHints() ]; } - public function testGenerateAutoNodeNameNoHint() + public function testGenerateAutoNodeNameNoHint(): void { $result = NodeHelper::generateAutoNodeName($this->usedNames, $this->namespaces, 'a'); $this->assertEquals('a:', substr($result, 0, 2)); @@ -64,12 +65,13 @@ public function testGenerateAutoNodeNameNoHint() /** * @dataProvider hints */ - public function testGenerateAutoNodeName($hint, $expect) + public function testGenerateAutoNodeName(string $hint, bool|string $expect): void { $result = NodeHelper::generateAutoNodeName($this->usedNames, $this->namespaces, 'a', $hint); if (true === $expect) { $this->assertStringNotContainsString(':', $result); } else { + $this->assertIsString($expect); $this->assertEquals($expect, substr($result, 0, strlen($expect))); } } @@ -77,15 +79,14 @@ public function testGenerateAutoNodeName($hint, $expect) /** * @dataProvider invalidHints */ - public function testGenerateAutoNodeNameInvalid($hint) + public function testGenerateAutoNodeNameInvalid(string $hint): void { $this->expectException(RepositoryException::class); NodeHelper::generateAutoNodeName($this->usedNames, $this->namespaces, 'a', $hint); } - public function testIsSystemItem() + public function testIsSystemItem(): void { - /** @var MockNode|MockObject $sys */ $sys = $this->createMock(MockNode::class); $sys->expects($this->once()) @@ -109,7 +110,6 @@ public function testIsSystemItem() $this->assertTrue(NodeHelper::isSystemItem($sys)); - /** @var MockNode|MockObject $top */ $top = $this->createMock(MockNode::class); $top->expects($this->once()) ->method('getDepth') @@ -121,7 +121,6 @@ public function testIsSystemItem() $this->assertFalse(NodeHelper::isSystemItem($top)); - /** @var MockNode|MockObject $deep */ $deep = $this->createMock(MockNode::class); $deep->expects($this->once()) ->method('getDepth') @@ -130,7 +129,7 @@ public function testIsSystemItem() $this->assertFalse(NodeHelper::isSystemItem($deep)); } - public function testCalculateOrderBeforeSwapLast() + public function testCalculateOrderBeforeSwapLast(): void { $old = ['one', 'two', 'three', 'four']; $new = ['one', 'two', 'four', 'three']; @@ -139,13 +138,13 @@ public function testCalculateOrderBeforeSwapLast() $expected = [ 'three' => null, - 'two' => 'four', // TODO: this is an unnecessary but harmless NOOP. we should try to eliminate + 'two' => 'four', // TODO: this is an unnecessary but harmless NOOP. we should try to eliminate ]; $this->assertEquals($expected, $reorders); } - public function testCalculateOrderBeforeSwap() + public function testCalculateOrderBeforeSwap(): void { $old = ['one', 'two', 'three', 'four']; $new = ['one', 'four', 'three', 'two']; @@ -154,13 +153,13 @@ public function testCalculateOrderBeforeSwap() $expected = [ 'three' => 'two', - 'two' => null, + 'two' => null, ]; $this->assertEquals($expected, $reorders); } - public function testCalculateOrderBeforeReverse() + public function testCalculateOrderBeforeReverse(): void { $old = ['one', 'two', 'three', 'four']; $new = ['four', 'three', 'two', 'one']; @@ -169,13 +168,13 @@ public function testCalculateOrderBeforeReverse() $expected = [ 'three' => 'two', - 'two' => 'one', - 'one' => null, + 'two' => 'one', + 'one' => null, ]; $this->assertEquals($expected, $reorders); } - public function testCalculateOrderBeforeDeleted() + public function testCalculateOrderBeforeDeleted(): void { $old = ['one', 'two', 'three', 'four']; $new = ['one', 'three', 'two']; @@ -183,8 +182,8 @@ public function testCalculateOrderBeforeDeleted() $reorders = NodeHelper::calculateOrderBefore($old, $new); $expected = [ - 'two' => null, - 'one' => 'three', // TODO: this is an unnecessary but harmless NOOP. we should try to eliminate + 'two' => null, + 'one' => 'three', // TODO: this is an unnecessary but harmless NOOP. we should try to eliminate ]; $this->assertEquals($expected, $reorders); @@ -193,11 +192,11 @@ public function testCalculateOrderBeforeDeleted() /** * @group benchmark */ - public function testBenchmarkOrderBeforeArray() + public function testBenchmarkOrderBeforeArray(): void { $nodes = []; - for ($i = 0; $i < 100000; $i++) { + for ($i = 0; $i < 100000; ++$i) { $nodes[] = 'test'.$i; } diff --git a/tests/PHPCR/Tests/Util/PathHelperTest.php b/tests/PHPCR/Tests/Util/PathHelperTest.php index 14d09116..5bafb693 100644 --- a/tests/PHPCR/Tests/Util/PathHelperTest.php +++ b/tests/PHPCR/Tests/Util/PathHelperTest.php @@ -1,12 +1,13 @@ assertTrue(PathHelper::assertValidAbsolutePath($path, $destination)); } - public function dataproviderValidAbsolutePaths() + /** + * @return array + */ + public static function dataproviderValidAbsolutePaths(): array { return [ ['/parent/child'], @@ -35,7 +39,7 @@ public function dataproviderValidAbsolutePaths() /** * @dataProvider dataproviderInvalidAbsolutePaths */ - public function testAssertInvalidAbsolutePath($path, $destination = false) + public function testAssertInvalidAbsolutePath(string $path, bool $destination = false): void { $this->expectException(RepositoryException::class); @@ -45,12 +49,15 @@ public function testAssertInvalidAbsolutePath($path, $destination = false) /** * @dataProvider dataproviderValidAbsolutePathsWithNamespaces */ - public function testAssertAbsolutePathNamespace($path) + public function testAssertAbsolutePathNamespace(string $path): void { $this->assertTrue(PathHelper::assertValidAbsolutePath($path, false, true, ['jcr', 'nt'])); } - public function dataproviderValidAbsolutePathsWithNamespaces() + /** + * @return array + */ + public function dataproviderValidAbsolutePathsWithNamespaces(): array { return [ ['/parent/child'], @@ -65,7 +72,7 @@ public function dataproviderValidAbsolutePathsWithNamespaces() ]; } - public function testAssertInvalidNamespaceAbsolutePath() + public function testAssertInvalidNamespaceAbsolutePath(): void { $this->expectException(NamespaceException::class); $this->expectExceptionMessage('invalidprefix and other-ns'); @@ -76,12 +83,15 @@ public function testAssertInvalidNamespaceAbsolutePath() /** * @dataProvider dataproviderInvalidAbsolutePaths */ - public function testAssertInvalidAbsolutePathNoThrow($path, $destination = false) + public function testAssertInvalidAbsolutePathNoThrow(string $path, bool $destination = false): void { $this->assertFalse(PathHelper::assertValidAbsolutePath($path, $destination, false)); } - public function dataproviderInvalidAbsolutePaths() + /** + * @return array + */ + public function dataproviderInvalidAbsolutePaths(): array { return [ ['/parent/child[7]', true], // destination last element with index @@ -96,12 +106,12 @@ public function dataproviderInvalidAbsolutePaths() // assertValidLocalName tests - public function testAssertValidLocalName() + public function testAssertValidLocalName(): void { $this->assertTrue(PathHelper::assertValidLocalName('nodename')); } - public function testAssertValidLocalNameRootnode() + public function testAssertValidLocalNameRootnode(): void { $this->assertTrue(PathHelper::assertValidLocalName('')); } @@ -109,14 +119,17 @@ public function testAssertValidLocalNameRootnode() /** * @dataProvider dataproviderInvalidLocalNames */ - public function testAssertInvalidLocalName($name) + public function testAssertInvalidLocalName(string $name): void { $this->expectException(RepositoryException::class); PathHelper::assertValidLocalName($name); } - public function dataproviderInvalidLocalNames() + /** + * @return array + */ + public static function dataproviderInvalidLocalNames(): array { return [ ['jcr:nodename'], @@ -131,12 +144,15 @@ public function dataproviderInvalidLocalNames() /** * @dataProvider dataproviderNormalizePath */ - public function testNormalizePath($inputPath, $outputPath) + public function testNormalizePath(string $inputPath, string $outputPath): void { $this->assertSame($outputPath, PathHelper::normalizePath($inputPath)); } - public static function dataproviderNormalizePath() + /** + * @return array + */ + public static function dataproviderNormalizePath(): array { return [ ['/', '/'], @@ -150,7 +166,7 @@ public static function dataproviderNormalizePath() /** * @dataProvider dataproviderNormalizePathInvalid */ - public function testNormalizePathInvalidThrow($input) + public function testNormalizePathInvalidThrow(string $input): void { $this->expectException(RepositoryException::class); @@ -160,19 +176,22 @@ public function testNormalizePathInvalidThrow($input) /** * @dataProvider dataproviderNormalizePathInvalid */ - public function testNormalizePathInvalidNoThrow($input) + public function testNormalizePathInvalidNoThrow(string $input): void { $this->assertFalse(PathHelper::normalizePath($input, true, false)); } - public static function dataproviderNormalizePathInvalid() + /** + * @return array + */ + public static function dataproviderNormalizePathInvalid(): array { return [ ['foo/bar'], ['bar'], ['/foo/bar/'], [''], - [new stdClass()], + ['//'], ]; } @@ -181,12 +200,15 @@ public static function dataproviderNormalizePathInvalid() /** * @dataProvider dataproviderAbsolutizePath */ - public function testAbsolutizePath($inputPath, $context, $outputPath) + public function testAbsolutizePath(string $inputPath, string $context, string $outputPath): void { $this->assertSame($outputPath, PathHelper::absolutizePath($inputPath, $context)); } - public static function dataproviderAbsolutizePath() + /** + * @return array + */ + public static function dataproviderAbsolutizePath(): array { return [ ['/../foo', '/', '/foo'], @@ -199,7 +221,7 @@ public static function dataproviderAbsolutizePath() /** * @dataProvider dataproviderAbsolutizePathInvalid */ - public function testAbsolutizePathInvalidThrow($inputPath, $context, $target) + public function testAbsolutizePathInvalidThrow(string $inputPath, string $context, bool $target): void { $this->expectException(RepositoryException::class); PathHelper::absolutizePath($inputPath, $context, $target); @@ -208,18 +230,20 @@ public function testAbsolutizePathInvalidThrow($inputPath, $context, $target) /** * @dataProvider dataproviderAbsolutizePathInvalid */ - public function testAbsolutizePathInvalidNoThrow($inputPath, $context, $target) + public function testAbsolutizePathInvalidNoThrow(string $inputPath, string $context, bool $target): void { $this->assertFalse(PathHelper::absolutizePath($inputPath, $context, $target, false)); } - public static function dataproviderAbsolutizePathInvalid() + /** + * @return array + */ + public static function dataproviderAbsolutizePathInvalid(): array { return [ ['', '/context', false], - [null, '/context', false], - ['foo', null, false], - [new stdClass(), '/context', false], + ['//', '/context', false], + ['foo', '//', false], ['foo[2]', '/bar', true], ]; } @@ -229,12 +253,15 @@ public static function dataproviderAbsolutizePathInvalid() /** * @dataProvider dataproviderRelativizePath */ - public function testRelativizePath($inputPath, $context, $outputPath) + public function testRelativizePath(string $inputPath, string $context, string $outputPath): void { $this->assertSame($outputPath, PathHelper::relativizePath($inputPath, $context)); } - public static function dataproviderRelativizePath() + /** + * @return array + */ + public static function dataproviderRelativizePath(): array { return [ ['/parent/path/child', '/parent', 'path/child'], @@ -245,7 +272,7 @@ public static function dataproviderRelativizePath() /** * @dataProvider dataproviderRelativizePathInvalid */ - public function testRelativizePathInvalidThrow($inputPath, $context) + public function testRelativizePathInvalidThrow(string $inputPath, string $context): void { $this->expectException(RepositoryException::class); @@ -255,12 +282,15 @@ public function testRelativizePathInvalidThrow($inputPath, $context) /** * @dataProvider dataproviderRelativizePathInvalid */ - public function testRelativizePathInvalidNoThrow($inputPath, $context) + public function testRelativizePathInvalidNoThrow(string $inputPath, string $context): void { $this->assertFalse(PathHelper::relativizePath($inputPath, $context, false)); } - public static function dataproviderRelativizePathInvalid() + /** + * @return array + */ + public static function dataproviderRelativizePathInvalid(): array { return [ ['/path', '/context'], @@ -273,12 +303,15 @@ public static function dataproviderRelativizePathInvalid() /** * @dataProvider dataproviderParentPath */ - public function testGetParentPath($path, $parent) + public function testGetParentPath(string $path, string $parent): void { $this->assertEquals($parent, PathHelper::getParentPath($path)); } - public function dataproviderParentPath() + /** + * @return array + */ + public function dataproviderParentPath(): array { return [ ['/parent/child', '/parent'], @@ -293,12 +326,15 @@ public function dataproviderParentPath() /** * @dataProvider dataproviderGetNodeName */ - public function testGetNodeName($path, $expected = null) + public function testGetNodeName(string $path, string $expected): void { $this->assertEquals($expected, PathHelper::getNodeName($path)); } - public function dataproviderGetNodeName() + /** + * @return array + */ + public function dataproviderGetNodeName(): array { return [ ['/parent/child', 'child'], @@ -310,12 +346,15 @@ public function dataproviderGetNodeName() /** * @dataProvider dataproviderGetLocalNodeName */ - public function testGetLocalNodeName($path, $expected = null) + public function testGetLocalNodeName(string $path, string $expected): void { $this->assertEquals($expected, PathHelper::getLocalNodeName($path)); } - public function dataproviderGetLocalNodeName() + /** + * @return array + */ + public function dataproviderGetLocalNodeName(): array { return [ ['/parent/child', 'child'], @@ -326,7 +365,7 @@ public function dataproviderGetLocalNodeName() ]; } - public function testGetNodeNameMustBeAbsolute() + public function testGetNodeNameMustBeAbsolute(): void { $this->expectException(RepositoryException::class); $this->expectExceptionMessage('must be an absolute path'); @@ -339,12 +378,15 @@ public function testGetNodeNameMustBeAbsolute() /** * @dataProvider dataproviderPathDepth */ - public function testGetPathDepth($path, $depth) + public function testGetPathDepth(string $path, int $depth): void { $this->assertEquals($depth, PathHelper::getPathDepth($path)); } - public function dataproviderPathDepth() + /** + * @return array + */ + public function dataproviderPathDepth(): array { return [ ['/', 0], diff --git a/tests/PHPCR/Tests/Util/QOM/BaseSqlGeneratorTest.php b/tests/PHPCR/Tests/Util/QOM/BaseSqlGeneratorTest.php index 0f11e57d..c89b55e3 100644 --- a/tests/PHPCR/Tests/Util/QOM/BaseSqlGeneratorTest.php +++ b/tests/PHPCR/Tests/Util/QOM/BaseSqlGeneratorTest.php @@ -1,5 +1,7 @@ generator->evalNot('foo = bar'); $this->assertSame('(NOT foo = bar)', $string); diff --git a/tests/PHPCR/Tests/Util/QOM/QueryBuilderTest.php b/tests/PHPCR/Tests/Util/QOM/QueryBuilderTest.php index a96ef099..b89f7e2a 100644 --- a/tests/PHPCR/Tests/Util/QOM/QueryBuilderTest.php +++ b/tests/PHPCR/Tests/Util/QOM/QueryBuilderTest.php @@ -1,8 +1,9 @@ getMock(); } - public function testSetFirstResult() + public function testSetFirstResult(): void { $qb = new QueryBuilder($this->qf); $qb->setFirstResult(15); $this->assertEquals(15, $qb->getFirstResult()); } - public function testSetMaxResults() + public function testSetMaxResults(): void { $qb = new QueryBuilder($this->qf); $qb->setMaxResults(15); @@ -58,7 +59,7 @@ private function createDynamicOperandMock() return $dynamicOperand; } - public function testAddOrderBy() + public function testAddOrderBy(): void { $dynamicOperand = $this->createDynamicOperandMock(); @@ -69,7 +70,7 @@ public function testAddOrderBy() $orderings = $qb->getOrderings(); } - public function testAddOrderByLowercase() + public function testAddOrderByLowercase(): void { $dynamicOperand = $this->createDynamicOperandMock(); @@ -80,9 +81,9 @@ public function testAddOrderByLowercase() $orderings = $qb->getOrderings(); } - public function testAddOrderByInvalid() + public function testAddOrderByInvalid(): void { - $this->expectException(InvalidArgumentException::class); + $this->expectException(\InvalidArgumentException::class); $dynamicOperand = $this->createDynamicOperandMock(); @@ -90,7 +91,7 @@ public function testAddOrderByInvalid() $qb->addOrderBy($dynamicOperand, 'FOO'); } - public function testOrderBy() + public function testOrderBy(): void { $dynamicOperand = $this->createDynamicOperandMock(); @@ -100,7 +101,7 @@ public function testOrderBy() $this->assertCount(1, $qb->getOrderings()); } - public function testOrderAscending() + public function testOrderAscending(): void { $dynamicOperand = $this->createDynamicOperandMock(); @@ -112,7 +113,7 @@ public function testOrderAscending() $qb->addOrderBy($dynamicOperand, 'ASC'); } - public function testOrderDescending() + public function testOrderDescending(): void { $dynamicOperand = $this->createDynamicOperandMock(); @@ -124,7 +125,7 @@ public function testOrderDescending() $qb->addOrderBy($dynamicOperand, 'DESC'); } - public function testOrderAscendingIsDefault() + public function testOrderAscendingIsDefault(): void { $dynamicOperand = $this->createDynamicOperandMock(); @@ -150,7 +151,7 @@ private function createConstraintMock() return $constraint; } - public function testWhere() + public function testWhere(): void { $constraint = $this->createConstraintMock(); @@ -159,7 +160,7 @@ public function testWhere() $this->assertEquals($constraint, $qb->getConstraint()); } - public function testAndWhere() + public function testAndWhere(): void { $this->qf->expects($this->once()) ->method('andConstraint'); @@ -172,7 +173,7 @@ public function testAndWhere() $qb->andWhere($constraint2); } - public function testOrWhere() + public function testOrWhere(): void { $this->qf->expects($this->once()) ->method('orConstraint'); @@ -185,7 +186,7 @@ public function testOrWhere() $qb->orWhere($constraint2); } - public function testSelect() + public function testSelect(): void { $qb = new QueryBuilder($this->qf); $this->assertCount(0, $qb->getColumns()); @@ -195,7 +196,7 @@ public function testSelect() $this->assertCount(1, $qb->getColumns()); } - public function testAddSelect() + public function testAddSelect(): void { $qb = new QueryBuilder($this->qf); $this->assertCount(0, $qb->getColumns()); @@ -219,7 +220,7 @@ private function createSourceMock() return $source; } - public function testFrom() + public function testFrom(): void { $source = $this->createSourceMock(); @@ -242,9 +243,9 @@ private function createSameNodeJoinConditionMock() return $joinCondition; } - public function testInvalidJoin() + public function testInvalidJoin(): void { - $this->expectException(RuntimeException::class); + $this->expectException(\RuntimeException::class); $source = $this->createSourceMock(); $joinCondition = $this->createSameNodeJoinConditionMock(); @@ -253,7 +254,7 @@ public function testInvalidJoin() $qb->join($source, $joinCondition); } - public function testJoin() + public function testJoin(): void { $source1 = $this->createSourceMock(); $source2 = $this->createSourceMock(); @@ -273,7 +274,7 @@ public function testJoin() $qb->join($source2, $joinCondition); } - public function testRightJoin() + public function testRightJoin(): void { $source1 = $this->createSourceMock(); $source2 = $this->createSourceMock(); @@ -293,7 +294,7 @@ public function testRightJoin() $qb->rightJoin($source2, $joinCondition); } - public function testLeftJoin() + public function testLeftJoin(): void { $source1 = $this->createSourceMock(); $source2 = $this->createSourceMock(); @@ -313,7 +314,7 @@ public function testLeftJoin() $qb->leftJoin($source2, $joinCondition); } - public function testGetQuery() + public function testGetQuery(): void { $source = $this->createSourceMock(); $constraint = $this->createConstraintMock(); @@ -324,17 +325,16 @@ public function testGetQuery() $this->qf->expects($this->once()) ->method('createQuery') - ->willReturn('true'); + ->willReturn($this->createMock(QueryObjectModelInterface::class)); $qb->getQuery(); } /** - * @return QueryObjectModelInterface|MockObject + * @return QueryObjectModelInterface&MockObject */ private function createQueryMock() { - /** @var QueryObjectModelInterface $query */ $query = $this->getMockBuilder(QueryObjectModelInterface::class) ->setMethods([]) ->setConstructorArgs([]) @@ -343,7 +343,7 @@ private function createQueryMock() return $query; } - public function testGetQueryWithOffsetAndLimit() + public function testGetQueryWithOffsetAndLimit(): void { $source = $this->createSourceMock(); $constraint = $this->createConstraintMock(); @@ -368,7 +368,7 @@ public function testGetQueryWithOffsetAndLimit() $qb->getQuery(); } - public function testSetParameter() + public function testSetParameter(): void { $key = 'key'; $value = 'value'; @@ -379,7 +379,7 @@ public function testSetParameter() $this->assertEquals($value, $qb->getParameter($key)); } - public function testSetParameters() + public function testSetParameters(): void { $key1 = 'key1'; $value1 = 'value1'; @@ -387,18 +387,24 @@ public function testSetParameters() $value2 = 'value2'; $qb = new QueryBuilder($this->qf); - $qb->setParameters([$key1, $value1], [$key2, $value2]); + $qb->setParameters([ + $key1 => $value1, + $key2 => $value2, + ]); $this->assertCount(2, $qb->getParameters()); } - public function testExecute() + public function testExecute(): void { $source = $this->createSourceMock(); $constraint = $this->createConstraintMock(); $query = $this->createQueryMock(); + $result = $this->createMock(QueryResultInterface::class); $query->expects($this->once()) - ->method('execute'); + ->method('execute') + ->willReturn($result) + ; $query->expects($this->once()) ->method('bindValue'); @@ -408,11 +414,14 @@ public function testExecute() ->willReturn($query); $qb = new QueryBuilder($this->qf); - $qb->from($source) - ->where($constraint) - ->setFirstResult(10) - ->setMaxResults(10) - ->setParameter('Key', 'value') - ->execute(); + $this->assertSame( + $result, + $qb->from($source) + ->where($constraint) + ->setFirstResult(10) + ->setMaxResults(10) + ->setParameter('Key', 'value') + ->execute() + ); } } diff --git a/tests/PHPCR/Tests/Util/QOM/Sql1GeneratorTest.php b/tests/PHPCR/Tests/Util/QOM/Sql1GeneratorTest.php index aa0a7aa9..8798c678 100644 --- a/tests/PHPCR/Tests/Util/QOM/Sql1GeneratorTest.php +++ b/tests/PHPCR/Tests/Util/QOM/Sql1GeneratorTest.php @@ -1,8 +1,9 @@ generator = new Sql1Generator(new ValueConverter()); } - public function testLiteral() + public function testLiteral(): void { $literal = $this->generator->evalLiteral('Foobar'); $this->assertEquals("'Foobar'", $literal); } - public function testDateTimeLiteral() + public function testDateTimeLiteral(): void { - $literal = $this->generator->evalLiteral(new DateTime('2011-12-23T00:00:00.000+00:00')); + $literal = $this->generator->evalLiteral(new \DateTime('2011-12-23T00:00:00.000+00:00')); $this->assertEquals("TIMESTAMP '2011-12-23T00:00:00.000+00:00'", $literal); } - public function testBoolLiteral() + public function testBoolLiteral(): void { $literal = $this->generator->evalLiteral(true); $this->assertEquals("'true'", $literal); } - public function testLongLiteral() + public function testLongLiteral(): void { $literal = $this->generator->evalLiteral(11); $this->assertSame('11', $literal); } - public function testDoubleLiteral() + public function testDoubleLiteral(): void { $literal = $this->generator->evalLiteral(11.0); $this->assertSame('11.0', $literal); } - public function testChildNode() + public function testChildNode(): void { $literal = $this->generator->evalChildNode('/'); $this->assertSame("jcr:path LIKE '/%' AND NOT jcr:path LIKE '/%/%'", $literal); @@ -58,7 +59,7 @@ public function testChildNode() $this->assertSame("jcr:path LIKE '/foo[%]/bar[%]/baz[%]/%' AND NOT jcr:path LIKE '/foo[%]/bar[%]/baz[%]/%/%'", $literal); } - public function testDescendantNode() + public function testDescendantNode(): void { $literal = $this->generator->evalDescendantNode('/'); $this->assertSame("jcr:path LIKE '/%'", $literal); @@ -67,29 +68,29 @@ public function testDescendantNode() $this->assertSame("jcr:path LIKE '/foo[%]/bar[%]/baz[%]/%'", $literal); } - public function testPopertyExistence() + public function testPopertyExistence(): void { $literal = $this->generator->evalPropertyExistence(null, 'foo'); $this->assertSame('foo IS NOT NULL', $literal); } - public function testFullTextSearch() + public function testFullTextSearch(): void { - $literal = $this->generator->evalFullTextSearch(null, "'foo'"); + $literal = $this->generator->evalFullTextSearch('', "'foo'"); $this->assertSame("CONTAINS(*, 'foo')", $literal); - $literal = $this->generator->evalFullTextSearch(null, "'foo'", 'bar'); + $literal = $this->generator->evalFullTextSearch('', "'foo'", 'bar'); $this->assertSame("CONTAINS(bar, 'foo')", $literal); } - public function testColumns() + public function testColumns(): void { - $literal = $this->generator->evalColumns(null); + $literal = $this->generator->evalColumns([]); $this->assertSame('s', $literal); $literal = $this->generator->evalColumns(['bar', 'foo']); $this->assertSame('bar, foo', $literal); } - public function testPropertyValue() + public function testPropertyValue(): void { $literal = $this->generator->evalPropertyValue('foo'); $this->assertSame('foo', $literal); diff --git a/tests/PHPCR/Tests/Util/QOM/Sql2GeneratorTest.php b/tests/PHPCR/Tests/Util/QOM/Sql2GeneratorTest.php index f28dff48..f7d8c761 100644 --- a/tests/PHPCR/Tests/Util/QOM/Sql2GeneratorTest.php +++ b/tests/PHPCR/Tests/Util/QOM/Sql2GeneratorTest.php @@ -1,8 +1,9 @@ generator = new Sql2Generator(new ValueConverter()); } - public function testLiteral() + public function testLiteral(): void { $literal = $this->generator->evalLiteral('Foobar'); $this->assertEquals("'Foobar'", $literal); } - public function testDateTimeLiteral() + public function testDateTimeLiteral(): void { - $literal = $this->generator->evalLiteral(new DateTime('2011-12-23T00:00:00.000+00:00')); + $literal = $this->generator->evalLiteral(new \DateTime('2011-12-23T00:00:00.000+00:00')); $this->assertEquals("CAST('2011-12-23T00:00:00.000+00:00' AS DATE)", $literal); } - public function testBoolLiteral() + public function testBoolLiteral(): void { $literal = $this->generator->evalLiteral(true); $this->assertEquals("CAST('true' AS BOOLEAN)", $literal); } - public function testLongLiteral() + public function testLongLiteral(): void { $literal = $this->generator->evalLiteral(11); $this->assertEquals("CAST('11' AS LONG)", $literal); } - public function testDoubleLiteral() + public function testDoubleLiteral(): void { $literal = $this->generator->evalLiteral(11.0); $this->assertEquals("CAST('11' AS DOUBLE)", $literal); } - public function testChildNode() + public function testChildNode(): void { $literal = $this->generator->evalChildNode('/foo/bar/baz'); $this->assertSame('ISCHILDNODE(/foo/bar/baz)', $literal); } - public function testDescendantNode() + public function testDescendantNode(): void { $literal = $this->generator->evalDescendantNode('/foo/bar/baz'); $this->assertSame('ISDESCENDANTNODE(/foo/bar/baz)', $literal); } - public function testPopertyExistence() + public function testPopertyExistence(): void { $literal = $this->generator->evalPropertyExistence(null, 'foo'); $this->assertSame('[foo] IS NOT NULL', $literal); } - public function testFullTextSearch() + public function testFullTextSearch(): void { $literal = $this->generator->evalFullTextSearch('data', "'foo'"); $this->assertSame("CONTAINS(data.*, 'foo')", $literal); @@ -74,15 +75,15 @@ public function testFullTextSearch() $this->assertSame("CONTAINS(data.[bar], 'foo')", $literal); } - public function testColumns() + public function testColumns(): void { - $literal = $this->generator->evalColumns(null); + $literal = $this->generator->evalColumns([]); $this->assertSame('*', $literal); $literal = $this->generator->evalColumns(['bar', 'foo']); $this->assertSame('bar, foo', $literal); } - public function testPropertyValue() + public function testPropertyValue(): void { $literal = $this->generator->evalPropertyValue('foo'); $this->assertSame('[foo]', $literal); diff --git a/tests/PHPCR/Tests/Util/QOM/Sql2ScannerTest.php b/tests/PHPCR/Tests/Util/QOM/Sql2ScannerTest.php index 4fca5913..9918d94b 100644 --- a/tests/PHPCR/Tests/Util/QOM/Sql2ScannerTest.php +++ b/tests/PHPCR/Tests/Util/QOM/Sql2ScannerTest.php @@ -1,5 +1,7 @@ expectTokensFromScanner($scanner, $expected); } + /** + * @return array + */ public function dataTestStringTokenization(): array { $multilineQuery = <<<'SQL' -SELECT page.* -FROM [nt:unstructured] AS page -WHERE name ="Hello world" -SQL; + SELECT page.* + FROM [nt:unstructured] AS page + WHERE name ="Hello world" + SQL; return [ 'single line query' => ['SELECT page.* FROM [nt:unstructured] AS page WHERE name ="Hello world"'], @@ -63,11 +68,11 @@ public function dataTestStringTokenization(): array ]; } - public function testEscapingStrings() + public function testEscapingStrings(): void { $sql = <<expectTokensFromScanner($scanner, $expected); } - public function testSQLEscapedStrings() + public function testSQLEscapedStrings(): void { $sql = "WHERE page.name = 'Hello, it''s me.'"; @@ -106,7 +111,7 @@ public function testSQLEscapedStrings() $this->expectTokensFromScanner($scanner, $expected); } - public function testSQLEscapedStrings2() + public function testSQLEscapedStrings2(): void { $sql = "WHERE page.name = 'Hello, it''' AND"; @@ -124,7 +129,7 @@ public function testSQLEscapedStrings2() $this->expectTokensFromScanner($scanner, $expected); } - public function testSquareBrackets() + public function testSquareBrackets(): void { $sql = 'WHERE ISSAMENODE(file, ["/home node"])'; @@ -142,7 +147,7 @@ public function testSquareBrackets() $this->expectTokensFromScanner($scanner, $expected); } - public function testSquareBracketsWithoutQuotes() + public function testSquareBracketsWithoutQuotes(): void { $sql = 'WHERE ISSAMENODE(file, [/home node])'; @@ -160,7 +165,7 @@ public function testSquareBracketsWithoutQuotes() $this->expectTokensFromScanner($scanner, $expected); } - public function testTokenizingWithMissingSpaces() + public function testTokenizingWithMissingSpaces(): void { $sql = 'SELECT * AS"all"'; @@ -175,7 +180,7 @@ public function testTokenizingWithMissingSpaces() $this->expectTokensFromScanner($scanner, $expected); } - public function testThrowingErrorOnUnclosedString() + public function testThrowingErrorOnUnclosedString(): void { $this->expectException(InvalidQueryException::class); new Sql2Scanner('SELECT page.* FROM [nt:unstructured] AS page WHERE name ="Hello '); @@ -185,10 +190,9 @@ public function testThrowingErrorOnUnclosedString() * Function to assert that the tokens the scanner finds match the expected output * and the entire expected output is consumed. * - * @param Sql2Scanner $scanner * @param array $expected */ - private function expectTokensFromScanner(Sql2Scanner $scanner, array $expected) + private function expectTokensFromScanner(Sql2Scanner $scanner, array $expected): void { $actualTokens = []; while ($token = $scanner->fetchNextToken()) { diff --git a/tests/PHPCR/Tests/Util/QOM/Sql2ToQomQueryConverterTest.php b/tests/PHPCR/Tests/Util/QOM/Sql2ToQomQueryConverterTest.php index 393e3e6b..d52beeed 100644 --- a/tests/PHPCR/Tests/Util/QOM/Sql2ToQomQueryConverterTest.php +++ b/tests/PHPCR/Tests/Util/QOM/Sql2ToQomQueryConverterTest.php @@ -1,5 +1,7 @@ converter = new Sql2ToQomQueryConverter($this->qomFactory, $this->valueConverter); } - public function testInvalid() + public function testInvalid(): void { $this->expectException(InvalidQueryException::class); $this->expectExceptionMessage('Error parsing query'); diff --git a/tests/PHPCR/Tests/Util/TraversingItemVisitorTest.php b/tests/PHPCR/Tests/Util/TraversingItemVisitorTest.php index e2330267..abc3be63 100644 --- a/tests/PHPCR/Tests/Util/TraversingItemVisitorTest.php +++ b/tests/PHPCR/Tests/Util/TraversingItemVisitorTest.php @@ -1,12 +1,14 @@ markTestSkipped('TODO: implement tests for breath and depth first and with and without limit'); } diff --git a/tests/PHPCR/Tests/Util/UUIDHelperTest.php b/tests/PHPCR/Tests/Util/UUIDHelperTest.php index 3e20505e..f6efc33d 100644 --- a/tests/PHPCR/Tests/Util/UUIDHelperTest.php +++ b/tests/PHPCR/Tests/Util/UUIDHelperTest.php @@ -1,5 +1,7 @@ assertEquals(1, preg_match('/^[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}$/', $id)); } - public function testIsUUID() + public function testIsUUID(): void { $this->assertTrue(UUIDHelper::isUUID('550e8400-e29b-41d4-a716-446655440000')); $this->assertTrue(UUIDHelper::isUUID('00000000-0000-0000-C000-000000000046')); diff --git a/tests/PHPCR/Tests/Util/ValueConverterTest.php b/tests/PHPCR/Tests/Util/ValueConverterTest.php index 65002a7c..28f0b87c 100644 --- a/tests/PHPCR/Tests/Util/ValueConverterTest.php +++ b/tests/PHPCR/Tests/Util/ValueConverterTest.php @@ -1,8 +1,9 @@ valueConverter = new ValueConverter(); } - public function dataConversionMatrix() + /** + * @return array + */ + public function dataConversionMatrix(): array { $stream = fopen('php://memory', '+rw'); + $this->assertIsResource($stream); fwrite($stream, 'test string'); rewind($stream); $dateStream = fopen('php://memory', '+rw'); + $this->assertIsResource($dateStream); fwrite($dateStream, '17.12.2010 GMT'); rewind($dateStream); $numberStream = fopen('php://memory', '+rw'); + $this->assertIsResource($numberStream); fwrite($numberStream, '123.456'); rewind($numberStream); $nameStream = fopen('php://memory', '+rw'); + $this->assertIsResource($nameStream); fwrite($nameStream, 'test'); rewind($nameStream); $uuidStream = fopen('php://memory', '+rw'); + $this->assertIsResource($uuidStream); fwrite($uuidStream, '38b7cf18-c417-477a-af0b-c1e92a290c9a'); rewind($uuidStream); - $datetimeLong = new DateTime(); + $datetimeLong = new \DateTime(); $datetimeLong->setTimestamp(123); $nodeMock = $this->createMock(MockNode::class); @@ -70,7 +76,7 @@ public function dataConversionMatrix() ['test string', PropertyType::STRING, 0.0, PropertyType::DOUBLE], ['249.39', PropertyType::STRING, 249.39, PropertyType::DOUBLE], ['test string', PropertyType::STRING, null, PropertyType::DATE], - ['17.12.2010 GMT', PropertyType::STRING, new DateTime('17.12.2010 GMT'), PropertyType::DATE], + ['17.12.2010 GMT', PropertyType::STRING, new \DateTime('17.12.2010 GMT'), PropertyType::DATE], ['test string', PropertyType::STRING, true, PropertyType::BOOLEAN], ['false', PropertyType::STRING, true, PropertyType::BOOLEAN], ['', PropertyType::STRING, false, PropertyType::BOOLEAN], @@ -91,7 +97,7 @@ public function dataConversionMatrix() [$stream, PropertyType::BINARY, 0.0, PropertyType::DOUBLE], [$numberStream, PropertyType::BINARY, 123.456, PropertyType::DOUBLE], [$stream, PropertyType::BINARY, null, PropertyType::DATE], - [$dateStream, PropertyType::BINARY, new DateTime('17.12.2010 GMT'), PropertyType::DATE], + [$dateStream, PropertyType::BINARY, new \DateTime('17.12.2010 GMT'), PropertyType::DATE], [$stream, PropertyType::BINARY, true, PropertyType::BOOLEAN], [$nameStream, PropertyType::BINARY, 'test', PropertyType::NAME], // TODO: should we move UUIDHelper to phpcr so we can check in PropertyType? [$stream, PropertyType::STRING, null, PropertyType::REFERENCE], @@ -268,14 +274,9 @@ public function dataConversionMatrix() /** * Skip binary target as its a special case. * - * @param mixed $value - * @param int $srcType PropertyType constant to convert from - * @param $expected - * @param $targetType - * * @dataProvider dataConversionMatrix */ - public function testConvertType($value, $srcType, $expected, $targetType) + public function testConvertType(mixed $value, int $srcType, mixed $expected, int $targetType): void { if (null === $expected) { try { @@ -286,9 +287,9 @@ public function testConvertType($value, $srcType, $expected, $targetType) $this->assertTrue(true); // make it assert something } } else { - if ($expected instanceof DateTime) { + if ($expected instanceof \DateTime) { $result = $this->valueConverter->convertType($value, $targetType, $srcType); - $this->assertInstanceOf(DateTime::class, $result); + $this->assertInstanceOf(\DateTime::class, $result); $this->assertEquals($expected->getTimestamp(), $result->getTimestamp()); } else { $this->assertSame($expected, $this->valueConverter->convertType($value, $targetType, $srcType)); @@ -296,7 +297,7 @@ public function testConvertType($value, $srcType, $expected, $targetType) } } - public function testConvertTypeToBinary() + public function testConvertTypeToBinary(): void { $stream = $this->valueConverter->convertType('test string', PropertyType::BINARY); $this->assertIsResource($stream); @@ -308,14 +309,16 @@ public function testConvertTypeToBinary() $string = stream_get_contents($stream); $this->assertEquals('test string', $string); - $date = new DateTime('20.12.2012'); + $date = new \DateTime('20.12.2012'); $stream = $this->valueConverter->convertType($date, PropertyType::BINARY); $this->assertIsResource($stream); $string = stream_get_contents($stream); - $readDate = new DateTime($string); + $this->assertIsString($string); + $readDate = new \DateTime($string); $this->assertEquals($date->getTimestamp(), $readDate->getTimestamp()); - $stream = fopen('php://memory', '+rw'); + $stream = fopen('php://memory', '+rwb'); + $this->assertIsResource($stream); fwrite($stream, 'test string'); rewind($stream); @@ -325,7 +328,7 @@ public function testConvertTypeToBinary() // if conversion to string works, should be fine for all others } - public function testConvertTypeArray() + public function testConvertTypeArray(): void { $result = $this->valueConverter->convertType( ['2012-01-10', '2012-02-12'], @@ -335,8 +338,8 @@ public function testConvertTypeArray() $this->assertIsArray($result); $this->assertCount(2, $result); - $this->assertInstanceOf(DateTime::class, $result[0]); - $this->assertInstanceOf(DateTime::class, $result[1]); + $this->assertInstanceOf(\DateTime::class, $result[0]); + $this->assertInstanceOf(\DateTime::class, $result[1]); $this->assertEquals('2012-01-10', $result[0]->format('Y-m-d')); $this->assertEquals('2012-02-12', $result[1]->format('Y-m-d')); @@ -345,47 +348,47 @@ public function testConvertTypeArray() $this->assertEquals([], $result); } - public function testConvertTypeAutodetect() + public function testConvertTypeAutodetect(): void { - $date = new DateTime('2012-10-10'); + $date = new \DateTime('2012-10-10'); $result = $this->valueConverter->convertType($date, PropertyType::STRING); - $result = new DateTime($result); + $result = new \DateTime($result); $this->assertEquals($date->getTimestamp(), $result->getTimestamp()); $result = $this->valueConverter->convertType('2012-03-13T21:00:55.000+01:00', PropertyType::DATE); - $this->assertInstanceOf(DateTime::class, $result); + $this->assertInstanceOf(\DateTime::class, $result); $this->assertEquals(1331668855, $result->getTimestamp()); } - public function testConvertTypeArrayInvalid() + public function testConvertTypeArrayInvalid(): void { $this->expectException(ValueFormatException::class); $this->valueConverter->convertType(['a', 'b', 'c'], PropertyType::NAME, PropertyType::REFERENCE); } - public function testConvertInvalidString() + public function testConvertInvalidString(): void { $this->expectException(ValueFormatException::class); $this->valueConverter->convertType($this, PropertyType::STRING); } - public function testConvertInvalidBinary() + public function testConvertInvalidBinary(): void { $this->expectException(ValueFormatException::class); $this->valueConverter->convertType($this, PropertyType::BINARY); } - public function testConvertInvalidDate() + public function testConvertInvalidDate(): void { $this->expectException(ValueFormatException::class); $this->valueConverter->convertType($this, PropertyType::DATE); } - public function testConvertNewNode() + public function testConvertNewNode(): void { $this->expectException(ValueFormatException::class); @@ -397,7 +400,7 @@ public function testConvertNewNode() $this->valueConverter->convertType($nodeMock, PropertyType::STRING); } - public function testConvertNonRefNode() + public function testConvertNonRefNode(): void { $this->expectException(ValueFormatException::class); @@ -414,7 +417,10 @@ public function testConvertNonRefNode() $this->valueConverter->convertType($nodeMock, PropertyType::STRING); } - public function dataDateTargetType() + /** + * @return array> + */ + public function dataDateTargetType(): array { return [ [PropertyType::STRING], @@ -428,14 +434,14 @@ public function dataDateTargetType() * * @dataProvider dataDateTargetType */ - public function testConvertInvalidDateValue($targettype) + public function testConvertInvalidDateValue(int $targettype): void { $this->expectException(RepositoryException::class); $this->valueConverter->convertType('', $targettype, PropertyType::DATE); } - public function testConvertTypeInvalidTarget() + public function testConvertTypeInvalidTarget(): void { $this->expectException(ValueFormatException::class); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index cabe0864..434d92b1 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,11 +1,13 @@ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache Software License 2.0 * - * @link http://phpcr.github.io/ + * @see http://phpcr.github.io/ */ // $file2 for run tests if phpcr-utils lib inside of vendor directory.