From 5f1daaadc92f60f384a93b2b119cdd7c7987fb36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bohusl=C3=A1vek?= Date: Tue, 11 Mar 2025 12:09:56 +0100 Subject: [PATCH 1/4] .github/workflows: Fix test action See This request has been automatically failed because it uses a deprecated version of `actions/upload-artifact: v2`. Learn more: https://github.blog/changelog/2024-02-13-deprecation-notice-v1-and-v2-of-the-artifact-actions/ --- .github/workflows/tests.yml | 47 ++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8959e6f..2b4b8c2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,29 +1,32 @@ name: Tests -on: [push, pull_request] +on: + push: + pull_request: jobs: - tests: - runs-on: ubuntu-latest - strategy: - matrix: - php: ['7.4', '8.0', '8.1', '8.2'] + tests: + runs-on: ubuntu-latest + strategy: + matrix: + php: ['7.4', '8.0', '8.1', '8.2'] + fail-fast: false - fail-fast: false + name: PHP ${{ matrix.php }} tests + steps: + - uses: actions/checkout@v4 - name: PHP ${{ matrix.php }} tests - steps: - - uses: actions/checkout@v2 - - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - extensions: mbstring, tokenizer, sqlite3 - coverage: none + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: mbstring, tokenizer, sqlite3 + coverage: none - - run: composer install --no-interaction --prefer-dist - - run: vendor/bin/tester tests -s -C - - if: failure() - uses: actions/upload-artifact@v2 - with: - name: output - path: tests/**/output + - run: composer install --no-interaction --prefer-dist + - run: vendor/bin/tester tests -s -C + + - if: failure() + uses: actions/upload-artifact@v4 + with: + name: output + path: tests/**/output From 2046e96ea2984fb5e6f19f093f78ccb22b8ac5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bohusl=C3=A1vek?= Date: Tue, 11 Mar 2025 10:41:13 +0100 Subject: [PATCH 2/4] Format all *.php code; add some missing typehints --- LeanMapperQuery/Caller.php | 1 - LeanMapperQuery/Entity.php | 14 ++++------ LeanMapperQuery/Exception/Exception.php | 1 - .../Exception/InvalidArgumentException.php | 1 - .../Exception/InvalidMethodCallException.php | 1 - .../InvalidRelationshipException.php | 1 - .../Exception/InvalidStateException.php | 1 - .../Exception/MemberAccessException.php | 1 - .../Exception/NonExistingMethodException.php | 1 - .../Exception/NotImplementedException.php | 1 - LeanMapperQuery/ICaster.php | 2 -- LeanMapperQuery/IQuery.php | 2 -- LeanMapperQuery/Query.php | 28 +++++++------------ .../QueryTarget/HasManyRelationshipTable.php | 1 - .../QueryTarget/HasManyTargetTable.php | 1 - LeanMapperQuery/QueryTarget/ITarget.php | 1 - tests/bootstrap.php | 6 ++-- 17 files changed, 18 insertions(+), 46 deletions(-) diff --git a/LeanMapperQuery/Caller.php b/LeanMapperQuery/Caller.php index 25b0f86..65a2b94 100644 --- a/LeanMapperQuery/Caller.php +++ b/LeanMapperQuery/Caller.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery; /** diff --git a/LeanMapperQuery/Entity.php b/LeanMapperQuery/Entity.php index aa66ede..0428fde 100644 --- a/LeanMapperQuery/Entity.php +++ b/LeanMapperQuery/Entity.php @@ -5,15 +5,9 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery; use LeanMapper; -use LeanMapper\Filtering; -use LeanMapper\Fluent; -use LeanMapper\Reflection\Property; -use LeanMapper\Relationship; -use LeanMapper\Result; use LeanMapperQuery\Caller; use LeanMapperQuery\Exception\InvalidArgumentException; use LeanMapperQuery\Exception\InvalidMethodCallException; @@ -21,6 +15,11 @@ use LeanMapperQuery\Exception\InvalidStateException; use LeanMapperQuery\Exception\MemberAccessException; use LeanMapperQuery\IQuery; +use LeanMapper\Filtering; +use LeanMapper\Fluent; +use LeanMapper\Reflection\Property; +use LeanMapper\Relationship; +use LeanMapper\Result; /** * @author Michal Bohuslávek @@ -83,7 +82,6 @@ public static function queryEntityProperty(LeanMapper\Entity $entity, $field, IQ $targetTable = $relationship->getTargetTable(); $referencingColumn = $relationship->getColumnReferencingSourceTable(); $rows = $entity->row->referencing($targetTable, $referencingColumn, new Filtering($filters), $strategy); - } elseif ($relationship instanceof Relationship\HasMany) { $filters[] = function (Fluent $fluent) use ($mapper, $query) { $query->applyQuery($fluent, $mapper, new QueryTarget\HasManyTargetTable); @@ -148,10 +146,8 @@ public function __call($name, array $arguments) list(, $method, $field) = $matches; $field = lcfirst($field); return $this->$method($field, $query); - } else { return parent::__call($name, $arguments); } } - } diff --git a/LeanMapperQuery/Exception/Exception.php b/LeanMapperQuery/Exception/Exception.php index 56cc0be..1fe2108 100644 --- a/LeanMapperQuery/Exception/Exception.php +++ b/LeanMapperQuery/Exception/Exception.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery\Exception; /** diff --git a/LeanMapperQuery/Exception/InvalidArgumentException.php b/LeanMapperQuery/Exception/InvalidArgumentException.php index cf8801d..e8426d9 100644 --- a/LeanMapperQuery/Exception/InvalidArgumentException.php +++ b/LeanMapperQuery/Exception/InvalidArgumentException.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery\Exception; /** diff --git a/LeanMapperQuery/Exception/InvalidMethodCallException.php b/LeanMapperQuery/Exception/InvalidMethodCallException.php index 1f0ab3d..e70e85c 100644 --- a/LeanMapperQuery/Exception/InvalidMethodCallException.php +++ b/LeanMapperQuery/Exception/InvalidMethodCallException.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery\Exception; /** diff --git a/LeanMapperQuery/Exception/InvalidRelationshipException.php b/LeanMapperQuery/Exception/InvalidRelationshipException.php index 982fceb..6ab1a11 100644 --- a/LeanMapperQuery/Exception/InvalidRelationshipException.php +++ b/LeanMapperQuery/Exception/InvalidRelationshipException.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery\Exception; /** diff --git a/LeanMapperQuery/Exception/InvalidStateException.php b/LeanMapperQuery/Exception/InvalidStateException.php index f016004..224edca 100644 --- a/LeanMapperQuery/Exception/InvalidStateException.php +++ b/LeanMapperQuery/Exception/InvalidStateException.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery\Exception; /** diff --git a/LeanMapperQuery/Exception/MemberAccessException.php b/LeanMapperQuery/Exception/MemberAccessException.php index 45b543e..dd81aea 100644 --- a/LeanMapperQuery/Exception/MemberAccessException.php +++ b/LeanMapperQuery/Exception/MemberAccessException.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery\Exception; /** diff --git a/LeanMapperQuery/Exception/NonExistingMethodException.php b/LeanMapperQuery/Exception/NonExistingMethodException.php index 5f1fd6c..598fd04 100644 --- a/LeanMapperQuery/Exception/NonExistingMethodException.php +++ b/LeanMapperQuery/Exception/NonExistingMethodException.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery\Exception; /** diff --git a/LeanMapperQuery/Exception/NotImplementedException.php b/LeanMapperQuery/Exception/NotImplementedException.php index f822598..4fd356a 100644 --- a/LeanMapperQuery/Exception/NotImplementedException.php +++ b/LeanMapperQuery/Exception/NotImplementedException.php @@ -4,7 +4,6 @@ * This file is part of the LeanMapperQuery extension * for the Lean Mapper library (http://leanmapper.com) */ - namespace LeanMapperQuery\Exception; class NotImplementedException extends Exception diff --git a/LeanMapperQuery/ICaster.php b/LeanMapperQuery/ICaster.php index 2aceec3..bbd17a6 100644 --- a/LeanMapperQuery/ICaster.php +++ b/LeanMapperQuery/ICaster.php @@ -5,14 +5,12 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery; use LeanMapper\Fluent; interface ICaster { - /** * @param Fluent $fluent * @param string $entityClass diff --git a/LeanMapperQuery/IQuery.php b/LeanMapperQuery/IQuery.php index 033e776..4edbdfc 100644 --- a/LeanMapperQuery/IQuery.php +++ b/LeanMapperQuery/IQuery.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery; use LeanMapper\Fluent; @@ -19,7 +18,6 @@ */ interface IQuery { - /** * @param Fluent $fluent * @param IMapper $mapper diff --git a/LeanMapperQuery/Query.php b/LeanMapperQuery/Query.php index 7ef30cf..6905115 100644 --- a/LeanMapperQuery/Query.php +++ b/LeanMapperQuery/Query.php @@ -5,29 +5,28 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery; use LeanMapper; +use LeanMapperQuery\Exception\InvalidArgumentException; +use LeanMapperQuery\Exception\InvalidRelationshipException; +use LeanMapperQuery\Exception\InvalidStateException; +use LeanMapperQuery\Exception\MemberAccessException; +use LeanMapperQuery\Exception\NonExistingMethodException; use LeanMapper\Fluent; use LeanMapper\IMapper; use LeanMapper\ImplicitFilters; use LeanMapper\Reflection\Property; use LeanMapper\Relationship; use LeanMapper\Result; -use LeanMapperQuery\Exception\InvalidArgumentException; -use LeanMapperQuery\Exception\InvalidRelationshipException; -use LeanMapperQuery\Exception\InvalidStateException; -use LeanMapperQuery\Exception\MemberAccessException; -use LeanMapperQuery\Exception\NonExistingMethodException; /** * @author Michal Bohuslávek * * @template T of \LeanMapper\Entity * - * @method $this where($cond, ...$args) - * @method $this orderBy($field) + * @method $this where(string $cond, mixed ...$args) + * @method $this orderBy(string $field) * @method $this asc(bool $asc = true) * @method $this desc(bool $desc = true) * @method $this limit(int $limit) @@ -231,7 +230,7 @@ private function traverseToRelatedEntity(&$currentTable, &$currentTableAlias, Pr $entityClass = $this->mapper->getEntityClass($currentTable); throw new InvalidRelationshipException("Property '{$property->getName()}' in entity '$entityClass' doesn't have any relationship."); } - $implicitFilters= []; + $implicitFilters = []; $propertyType = $property->getType(); if (is_subclass_of($propertyType, 'LeanMapper\\Entity')) { $caller = new Caller($this, $property); @@ -245,14 +244,12 @@ private function traverseToRelatedEntity(&$currentTable, &$currentTableAlias, Pr $referencingColumn = $relationship->getColumnReferencingTargetTable(); // Join table. $targetTableAlias = $this->joinRelatedTable($currentTableAlias, $referencingColumn, $targetTable, $targetTablePrimaryKey, $implicitFilters, false); - } elseif ($relationship instanceof Relationship\BelongsTo) { // BelongsToOne, BelongsToMany $targetTable = $relationship->getTargetTable(); $sourceTablePrimaryKey = $this->mapper->getPrimaryKey($currentTable); $referencingColumn = $relationship->getColumnReferencingSourceTable(); // Join table. $targetTableAlias = $this->joinRelatedTable($currentTableAlias, $sourceTablePrimaryKey, $targetTable, $referencingColumn, $implicitFilters); - } elseif ($relationship instanceof Relationship\HasMany) { $sourceTablePrimaryKey = $this->mapper->getPrimaryKey($currentTable); $relationshipTable = $relationship->getRelationshipTable(); @@ -265,7 +262,6 @@ private function traverseToRelatedEntity(&$currentTable, &$currentTableAlias, Pr // Don't apply filters on relationship table. $relationshipTableAlias = $this->joinRelatedTable($currentTableAlias, $sourceTablePrimaryKey, $relationshipTable, $sourceReferencingColumn); $targetTableAlias = $this->joinRelatedTable($relationshipTableAlias, $targetReferencingColumn, $targetTable, $targetTablePrimaryKey, $implicitFilters, false); - } else { throw new InvalidRelationshipException('Unknown relationship type in property {$property->getName()}.'); } @@ -287,7 +283,7 @@ private function replacePlaceholder(Property $property) if ($type === 'DateTime' || is_subclass_of($type, 'DateTime')) { if ($property->hasCustomFlag(self::$typeFlagName) && preg_match('#^(DATE|Date|date)$#', $property->getCustomFlagValue(self::$typeFlagName))) { - return self::$placeholders['Date']; + return self::$placeholders['Date']; } else { return self::$placeholders['DateTime']; } @@ -327,7 +323,6 @@ protected function parseStatement($statement, $replacePlaceholders = null) if ($this->castedEntityClass) { list($rootEntityClass, $rootProperties) = $this->getPropertiesByEntity($this->castedEntityClass); - } else { list($rootEntityClass, $rootProperties) = $this->getPropertiesByTable($rootTableName); } @@ -405,7 +400,6 @@ protected function parseStatement($statement, $replacePlaceholders = null) $properties = $rootProperties; $tableNameAlias = $tableName = $rootTableName; $entityClass = $rootEntityClass; - } elseif ($replacePlaceholders && $ch === self::$defaultPlaceholder && $switches["'"] === false && $switches['"'] === false) { if ($property === null) { $output .= $ch; @@ -479,14 +473,12 @@ public function applyQuery(Fluent $fluent, IMapper $mapper, QueryTarget\ITarget $relationship->getRelationshipTable(), $relationship->getColumnReferencingTargetTable(), $targetTable, - $mapper->getPrimaryKey($targetTable) + $mapper->getPrimaryKey($targetTable), ); } - } elseif ($target instanceof QueryTarget\HasManyTargetTable) { $fluent->removeClause('LIMIT'); $fluent->removeClause('OFFSET'); - } elseif ($target !== null) { throw new InvalidArgumentException('Unsupported query target.'); } diff --git a/LeanMapperQuery/QueryTarget/HasManyRelationshipTable.php b/LeanMapperQuery/QueryTarget/HasManyRelationshipTable.php index ba2df3c..b3f2679 100644 --- a/LeanMapperQuery/QueryTarget/HasManyRelationshipTable.php +++ b/LeanMapperQuery/QueryTarget/HasManyRelationshipTable.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery\QueryTarget; use LeanMapper\Relationship; diff --git a/LeanMapperQuery/QueryTarget/HasManyTargetTable.php b/LeanMapperQuery/QueryTarget/HasManyTargetTable.php index 5fc96dc..54ad411 100644 --- a/LeanMapperQuery/QueryTarget/HasManyTargetTable.php +++ b/LeanMapperQuery/QueryTarget/HasManyTargetTable.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery\QueryTarget; class HasManyTargetTable implements ITarget diff --git a/LeanMapperQuery/QueryTarget/ITarget.php b/LeanMapperQuery/QueryTarget/ITarget.php index b0a3054..360fc2d 100644 --- a/LeanMapperQuery/QueryTarget/ITarget.php +++ b/LeanMapperQuery/QueryTarget/ITarget.php @@ -5,7 +5,6 @@ * for the Lean Mapper library (http://leanmapper.com) * Copyright (c) 2013 Michal Bohuslávek */ - namespace LeanMapperQuery\QueryTarget; interface ITarget diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 1a03b76..f6a40d4 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,10 +1,10 @@ 'sqlite3', - 'database' => __DIR__ . '/db/library.sq3', + 'driver' => 'sqlite3', + 'database' => __DIR__ . '/db/library.sq3', ]); $mapper = new TestMapper; From bf8c7abd42e4c2d4e477d694938132c9da106f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bohusl=C3=A1vek?= Date: Tue, 11 Mar 2025 10:55:45 +0100 Subject: [PATCH 3/4] Ignore some PHPStan errors --- LeanMapperQuery/Query.php | 10 +++++----- composer.json | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/LeanMapperQuery/Query.php b/LeanMapperQuery/Query.php index 6905115..cc696de 100644 --- a/LeanMapperQuery/Query.php +++ b/LeanMapperQuery/Query.php @@ -583,7 +583,7 @@ public function __call($name, array $args) /////////////// basic commands ////////////////////// - private function commandWhere($cond) + private function commandWhere($cond) // @phpstan-ignore-line { if (is_array($cond)) { if (func_num_args() > 1) { @@ -647,7 +647,7 @@ private function replaceEntitiesForItsPrimaryKeyValues(array $entities) return $entities; } - private function commandOrderBy($field) + private function commandOrderBy($field) // @phpstan-ignore-line { if (is_array($field)) { foreach ($field as $key => $value) { @@ -668,17 +668,17 @@ private function commandAsc($asc = true) $this->fluent->{$asc ? 'asc' : 'desc'}(); } - private function commandDesc($desc = true) + private function commandDesc($desc = true) // @phpstan-ignore-line { $this->commandAsc(!$desc); } - private function commandLimit($limit) + private function commandLimit($limit) // @phpstan-ignore-line { $this->fluent->limit($limit); } - private function commandOffset($offset) + private function commandOffset($offset) // @phpstan-ignore-line { $this->fluent->offset($offset); } diff --git a/composer.json b/composer.json index a3d2b9e..f6812eb 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ ], "scripts": { "test": "vendor/bin/tester tests -s", - "vet": "phpstan analyse -c phpstan.neon --no-progress --no-ansi --error-format raw" + "vet": "phpstan analyse -c phpstan.neon --no-progress --memory-limit 2G --no-ansi --error-format raw" }, "autoload": { "psr-0": { @@ -23,6 +23,6 @@ }, "require-dev": { "nette/tester": "~2.3.4", - "phpstan/phpstan": "~1.8" + "phpstan/phpstan": "^1.8" } } From f08761dc930ad3472e5d950504a18f9b411cac6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bohusl=C3=A1vek?= Date: Tue, 11 Mar 2025 10:51:32 +0100 Subject: [PATCH 4/4] Add support for args in Query::orderBy --- LeanMapperQuery/Query.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/LeanMapperQuery/Query.php b/LeanMapperQuery/Query.php index cc696de..b7f549d 100644 --- a/LeanMapperQuery/Query.php +++ b/LeanMapperQuery/Query.php @@ -26,7 +26,7 @@ * @template T of \LeanMapper\Entity * * @method $this where(string $cond, mixed ...$args) - * @method $this orderBy(string $field) + * @method $this orderBy(string $field, mixed ...$args) * @method $this asc(bool $asc = true) * @method $this desc(bool $desc = true) * @method $this limit(int $limit) @@ -658,8 +658,13 @@ private function commandOrderBy($field) // @phpstan-ignore-line } } } else { - $field = $this->parseStatement($field); - $this->fluent->orderBy($field); + $args = func_get_args(); + // Only first argument is parsed. Other arguments will be maintained + // as parameters. + $statement = &$args[0]; + $statement = $this->parseStatement($statement, null); + $args = $this->replaceEntitiesForItsPrimaryKeyValues($args); + call_user_func_array([$this->fluent, 'orderBy'], $args); } }