diff --git a/composer.json b/composer.json index 54118d3..f9ae255 100644 --- a/composer.json +++ b/composer.json @@ -15,25 +15,25 @@ "pull-request": "https://github.com/hyperf/hyperf/pulls" }, "require": { - "php": ">=8.1", - "hyperf/code-parser": "~3.1.0", - "hyperf/collection": "~3.1.23", - "hyperf/conditionable": "~3.1.0", - "hyperf/context": "~3.1.0", - "hyperf/contract": "~3.1.0", + "php": ">=8.2", + "hyperf/code-parser": "~3.2.0", + "hyperf/collection": "~3.2.0", + "hyperf/conditionable": "~3.2.0", + "hyperf/context": "~3.2.0", + "hyperf/contract": "~3.2.0", "hyperf/engine": "^2.0", - "hyperf/macroable": "~3.1.0", - "hyperf/stringable": "~3.1.0", - "hyperf/support": "~3.1.0", - "hyperf/tappable": "~3.1.0", - "nesbot/carbon": "^2.0", + "hyperf/macroable": "~3.2.0", + "hyperf/stringable": "~3.2.0", + "hyperf/support": "~3.2.0", + "hyperf/tappable": "~3.2.0", + "nesbot/carbon": "^2.0 || ^3.0", "psr/container": "^1.0 || ^2.0", "psr/event-dispatcher": "^1.0" }, "suggest": { "doctrine/dbal": "Required to rename columns (^3.0).", - "hyperf/paginator": "Required to paginate the result set (~3.1.0).", - "nikic/php-parser": "Required to use ModelCommand. (^4.0)", + "hyperf/paginator": "Required to paginate the result set (~3.2.0).", + "nikic/php-parser": "Required to use ModelCommand. (^5.0)", "php-di/phpdoc-reader": "Required to use ModelCommand. (^2.2)" }, "autoload": { diff --git a/src/Commands/Ast/GenerateModelIDEVisitor.php b/src/Commands/Ast/GenerateModelIDEVisitor.php index 29f74af..7c5f031 100644 --- a/src/Commands/Ast/GenerateModelIDEVisitor.php +++ b/src/Commands/Ast/GenerateModelIDEVisitor.php @@ -113,10 +113,10 @@ public function afterTraverse(array $nodes) } $argType = new Node\UnionType($unionTypeIdentifier); } else { - $argType = $argumentType->getName(); - if ($argumentType->allowsNull()) { - $argType = new Node\NullableType($argType); - } + $argType = PhpParser::getInstance()->getNodeByTypeString( + $argumentType->getName(), + $argumentType->allowsNull() + ); } } if ($argument->isDefaultValueAvailable()) { diff --git a/src/Commands/Ast/ModelUpdateVisitor.php b/src/Commands/Ast/ModelUpdateVisitor.php index 8adb28b..2dd6e12 100644 --- a/src/Commands/Ast/ModelUpdateVisitor.php +++ b/src/Commands/Ast/ModelUpdateVisitor.php @@ -86,13 +86,13 @@ public function beforeTraverse(array $nodes) public function leaveNode(Node $node) { switch ($node) { - case $node instanceof Node\Stmt\UseUse: + case $node instanceof Node\UseItem: $parts = $node->name->getParts(); - $class = implode('\\', $parts); + $class = $node->name->toString(); $alias = $node->alias?->name ?? array_pop($parts); $this->uses[$class] = $alias; return $node; - case $node instanceof Node\Stmt\PropertyProperty: + case $node instanceof Node\PropertyItem: if ((string) $node->name === 'fillable' && $this->option->isRefreshFillable()) { $node = $this->rewriteFillable($node); } elseif ((string) $node->name === 'casts') { @@ -107,11 +107,11 @@ public function leaveNode(Node $node) return null; } - protected function rewriteFillable(Node\Stmt\PropertyProperty $node): Node\Stmt\PropertyProperty + protected function rewriteFillable(Node\PropertyItem $node): Node\PropertyItem { $items = []; foreach ($this->columns as $column) { - $items[] = new Node\Expr\ArrayItem(new Node\Scalar\String_($column['column_name'])); + $items[] = new Node\ArrayItem(new Node\Scalar\String_($column['column_name'])); } $node->default = new Node\Expr\Array_($items, [ @@ -120,7 +120,7 @@ protected function rewriteFillable(Node\Stmt\PropertyProperty $node): Node\Stmt\ return $node; } - protected function rewriteCasts(Node\Stmt\PropertyProperty $node): Node\Stmt\PropertyProperty + protected function rewriteCasts(Node\PropertyItem $node): Node\PropertyItem { $items = []; $keys = []; @@ -150,7 +150,7 @@ protected function rewriteCasts(Node\Stmt\PropertyProperty $node): Node\Stmt\Pro continue; } if ($type || $type = $this->formatDatabaseType($column['data_type'])) { - $items[] = new Node\Expr\ArrayItem( + $items[] = new Node\ArrayItem( new Node\Scalar\String_($type), new Node\Scalar\String_($name) ); diff --git a/src/Commands/ModelCommand.php b/src/Commands/ModelCommand.php index 91e3118..42162d0 100644 --- a/src/Commands/ModelCommand.php +++ b/src/Commands/ModelCommand.php @@ -22,8 +22,6 @@ use Hyperf\Database\Model\Model; use Hyperf\Database\Schema\Builder; use Hyperf\Stringable\Str; -use PhpParser\Lexer; -use PhpParser\Lexer\Emulative; use PhpParser\NodeTraverser; use PhpParser\NodeVisitor\CloningVisitor; use PhpParser\Parser; @@ -44,8 +42,6 @@ class ModelCommand extends Command protected ?ConfigInterface $config = null; - protected ?Lexer $lexer = null; - protected ?Parser $astParser = null; protected ?PrettyPrinterAbstract $printer = null; @@ -60,14 +56,7 @@ public function run(InputInterface $input, OutputInterface $output): int { $this->resolver = $this->container->get(ConnectionResolverInterface::class); $this->config = $this->container->get(ConfigInterface::class); - $this->lexer = new Emulative([ - 'usedAttributes' => [ - 'comments', - 'startLine', 'endLine', - 'startTokenPos', 'endTokenPos', - ], - ]); - $this->astParser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7, $this->lexer); + $this->astParser = (new ParserFactory())->createForNewestSupportedVersion(); $this->printer = new Standard(); return parent::run($input, $output); @@ -197,7 +186,7 @@ protected function createModel(string $table, ModelOption $option): void $traverser->addVisitor(new CloningVisitor()); $originStmts = $this->astParser->parse(file_get_contents($path)); - $originTokens = $this->lexer->getTokens(); + $originTokens = $this->astParser->getTokens(); $newStmts = $traverser->traverse($originStmts); $code = $this->printer->printFormatPreserving($newStmts, $originStmts, $originTokens); diff --git a/src/Connection.php b/src/Connection.php index bd564bf..1ba7824 100755 --- a/src/Connection.php +++ b/src/Connection.php @@ -977,6 +977,9 @@ public function setTablePrefix(string $prefix): static /** * Set the table prefix and return the grammar. + * @template T of Grammar + * @param T $grammar + * @return T */ public function withTablePrefix(Grammar $grammar): Grammar { @@ -1186,13 +1189,15 @@ protected function runQueryCallback(string $query, array $bindings, Closure $cal throw new UniqueConstraintViolationException( $query, $this->prepareBindings($bindings), - $e + $e, + $this->getName(), ); } throw new QueryException( $query, $this->prepareBindings($bindings), - $e + $e, + $this->getName() ); } catch (Throwable $throwable) { ++$this->errorCount; diff --git a/src/Connectors/Connector.php b/src/Connectors/Connector.php index 7b424d2..5f151cc 100755 --- a/src/Connectors/Connector.php +++ b/src/Connectors/Connector.php @@ -104,7 +104,9 @@ public function setDefaultOptions(array $options) */ protected function createPdoConnection($dsn, $username, $password, $options) { - return new PDO($dsn, $username, $password, $options); + return PHP_VERSION_ID < 80400 + ? new PDO($dsn, $username, $password, $options) + : PDO::connect($dsn, $username, $password, $options); /* @phpstan-ignore staticMethod.notFound (PHP 8.4) */ } /** diff --git a/src/Exception/QueryException.php b/src/Exception/QueryException.php index cfb936c..9766b14 100644 --- a/src/Exception/QueryException.php +++ b/src/Exception/QueryException.php @@ -26,8 +26,12 @@ class QueryException extends PDOException * @param string $sql the SQL for the query * @param array $bindings the bindings for the query */ - public function __construct(protected string $sql, protected array $bindings, Exception $previous) - { + public function __construct( + protected string $sql, + protected array $bindings, + Exception $previous, + public ?string $connectionName = null, + ) { parent::__construct('', 0, $previous); $this->code = $previous->getCode(); diff --git a/src/Model/Builder.php b/src/Model/Builder.php index 55332ff..b9cded3 100755 --- a/src/Model/Builder.php +++ b/src/Model/Builder.php @@ -124,45 +124,42 @@ public function __construct(QueryBuilder $query) /** * Dynamically handle calls into the query instance. - * - * @param string $method - * @param array $parameters */ - public function __call($method, $parameters) + public function __call(string $name, array $arguments): mixed { - if ($method === 'macro') { - $this->localMacros[$parameters[0]] = $parameters[1]; + if ($name === 'macro') { + $this->localMacros[$arguments[0]] = $arguments[1]; - return; + return null; } - if ($method === 'mixin') { - return static::registerMixin($parameters[0], $parameters[1] ?? true); + if ($name === 'mixin') { + return static::registerMixin($arguments[0], $arguments[1] ?? true); } - if ($this->hasMacro($method)) { - array_unshift($parameters, $this); + if ($this->hasMacro($name)) { + array_unshift($arguments, $this); - return $this->localMacros[$method](...$parameters); + return $this->localMacros[$name](...$arguments); } - if (static::hasGlobalMacro($method)) { - if (static::$macros[$method] instanceof Closure) { - return call_user_func_array(static::$macros[$method]->bindTo($this, static::class), $parameters); + if (static::hasGlobalMacro($name)) { + if (static::$macros[$name] instanceof Closure) { + return call_user_func_array(static::$macros[$name]->bindTo($this, static::class), $arguments); } - return call_user_func_array(static::$macros[$method], $parameters); + return call_user_func_array(static::$macros[$name], $arguments); } - if (isset($this->model) && method_exists($this->model, $scope = 'scope' . ucfirst($method))) { - return $this->callScope([$this->model, $scope], $parameters); + if (isset($this->model) && method_exists($this->model, $scope = 'scope' . ucfirst($name))) { + return $this->callScope([$this->model, $scope], $arguments); } - if (in_array($method, $this->passthru)) { - return $this->toBase()->{$method}(...$parameters); + if (in_array($name, $this->passthru)) { + return $this->toBase()->{$name}(...$arguments); } - $this->query->{$method}(...$parameters); + $this->query->{$name}(...$arguments); return $this; } diff --git a/src/Model/Concerns/HasAttributes.php b/src/Model/Concerns/HasAttributes.php index 7fba994..6b13f8c 100644 --- a/src/Model/Concerns/HasAttributes.php +++ b/src/Model/Concerns/HasAttributes.php @@ -1220,7 +1220,7 @@ protected function asDateTime(mixed $value): CarbonInterface // and format a Carbon object from this timestamp. This allows flexibility // when defining your date fields as they might be UNIX timestamps here. if (is_numeric($value)) { - return Carbon::createFromTimestamp($value); + return Carbon::createFromTimestamp($value, date_default_timezone_get()); } // If the value is in simply year, month, day format, we will instantiate the diff --git a/src/Model/Concerns/HasUlids.php b/src/Model/Concerns/HasUlids.php index c6b067c..531b96e 100644 --- a/src/Model/Concerns/HasUlids.php +++ b/src/Model/Concerns/HasUlids.php @@ -16,6 +16,8 @@ trait HasUlids { + use HasUniqueStringIds; + /** * Generate a new ULID for the model. * @@ -27,40 +29,12 @@ public function newUniqueId() } /** - * Get the columns that should receive a unique identifier. - * - * @return array - */ - public function uniqueIds() - { - return [$this->getKeyName()]; - } - - /** - * Get the auto-incrementing key type. - * - * @return string - */ - public function getKeyType() - { - if (in_array($this->getKeyName(), $this->uniqueIds())) { - return 'string'; - } - - return $this->keyType; - } - - /** - * Get the value indicating whether the IDs are incrementing. + * Determine if given key is valid. * - * @return bool + * @param mixed $value */ - public function getIncrementing() + protected function isValidUniqueId($value): bool { - if (in_array($this->getKeyName(), $this->uniqueIds())) { - return false; - } - - return $this->incrementing; + return Str::isUlid($value); } } diff --git a/src/Model/Concerns/HasUniqueStringIds.php b/src/Model/Concerns/HasUniqueStringIds.php new file mode 100644 index 0000000..86b4de7 --- /dev/null +++ b/src/Model/Concerns/HasUniqueStringIds.php @@ -0,0 +1,108 @@ +getKeyName()]; + } + + /** + * Retrieve the model for a bound value. + * + * @param \Hyperf\Database\Model\Model|\Hyperf\Database\Model\Relations\Relation<*, *, *> $query + * @param mixed $value + * @param null|string $field + * @return Builder + * + * @throws ModelNotFoundException + */ + public function resolveRouteBindingQuery($query, $value, $field = null) + { + if ($field && in_array($field, $this->uniqueIds()) && ! $this->isValidUniqueId($value)) { + $this->handleInvalidUniqueId($value, $field); + } + + if (! $field && in_array($this->getRouteKeyName(), $this->uniqueIds()) && ! $this->isValidUniqueId($value)) { + $this->handleInvalidUniqueId($value, $field); + } + + return parent::resolveRouteBindingQuery($query, $value, $field); + } + + /** + * Get the auto-incrementing key type. + * + * @return string + */ + public function getKeyType() + { + if (in_array($this->getKeyName(), $this->uniqueIds())) { + return 'string'; + } + + return $this->keyType; + } + + /** + * Get the value indicating whether the IDs are incrementing. + * + * @return bool + */ + public function getIncrementing() + { + if (in_array($this->getKeyName(), $this->uniqueIds())) { + return false; + } + + return $this->incrementing; + } + + /** + * Throw an exception for the given invalid unique ID. + * + * @param mixed $value + * @param null|string $field + * @return never + * + * @throws ModelNotFoundException + */ + protected function handleInvalidUniqueId($value, $field) + { + throw (new ModelNotFoundException())->setModel(get_class($this), $value); + } + + /** + * Determine if given key is valid. + * + * @param mixed $value + */ + abstract protected function isValidUniqueId($value): bool; +} diff --git a/src/Model/Concerns/HasUuids.php b/src/Model/Concerns/HasUuids.php index 5d27dbe..6a8215f 100644 --- a/src/Model/Concerns/HasUuids.php +++ b/src/Model/Concerns/HasUuids.php @@ -16,6 +16,8 @@ trait HasUuids { + use HasUniqueStringIds; + /** * Generate a new UUID for the model. * @@ -27,40 +29,12 @@ public function newUniqueId() } /** - * Get the columns that should receive a unique identifier. - * - * @return array - */ - public function uniqueIds() - { - return [$this->getKeyName()]; - } - - /** - * Get the auto-incrementing key type. - * - * @return string - */ - public function getKeyType() - { - if (in_array($this->getKeyName(), $this->uniqueIds())) { - return 'string'; - } - - return $this->keyType; - } - - /** - * Get the value indicating whether the IDs are incrementing. + * Determine if given key is valid. * - * @return bool + * @param mixed $value */ - public function getIncrementing() + protected function isValidUniqueId($value): bool { - if (in_array($this->getKeyName(), $this->uniqueIds())) { - return false; - } - - return $this->incrementing; + return Str::isUuid($value); } } diff --git a/src/Model/Model.php b/src/Model/Model.php index 742b9e0..d3bb9cf 100644 --- a/src/Model/Model.php +++ b/src/Model/Model.php @@ -180,21 +180,18 @@ public function __unset($key) /** * Handle dynamic method calls into the model. - * - * @param string $method - * @param array $parameters */ - public function __call($method, $parameters) + public function __call(string $name, array $arguments): mixed { - if (in_array($method, ['increment', 'decrement'])) { - return $this->{$method}(...$parameters); + if (in_array($name, ['increment', 'decrement'])) { + return $this->{$name}(...$arguments); } - if ($resolver = $this->relationResolver(static::class, $method)) { + if ($resolver = $this->relationResolver(static::class, $name)) { return $resolver($this); } - return $this->newQuery()->{$method}(...$parameters); + return $this->newQuery()->{$name}(...$arguments); } /** @@ -886,10 +883,9 @@ public function toArray(): array * Convert the model instance to JSON. * * @param int $options - * @return string * @throws JsonEncodingException */ - public function toJson($options = 0) + public function toJson($options = 0): string { try { $json = json_encode($this->jsonSerialize(), $options | JSON_THROW_ON_ERROR); diff --git a/src/Model/Relations/MorphTo.php b/src/Model/Relations/MorphTo.php index 0269453..5a5788d 100644 --- a/src/Model/Relations/MorphTo.php +++ b/src/Model/Relations/MorphTo.php @@ -80,17 +80,14 @@ public function __construct(Builder $query, Model $parent, $foreignKey, $ownerKe /** * Handle dynamic method calls to the relationship. - * - * @param string $method - * @param array $parameters */ - public function __call($method, $parameters) + public function __call(string $name, array $arguments): mixed { try { - $result = parent::__call($method, $parameters); + $result = parent::__call($name, $arguments); - if (in_array($method, ['select', 'selectRaw', 'selectSub', 'addSelect', 'withoutGlobalScopes'])) { - $this->macroBuffer[] = compact('method', 'parameters'); + if (in_array($name, ['select', 'selectRaw', 'selectSub', 'addSelect', 'withoutGlobalScopes'])) { + $this->macroBuffer[] = compact('name', 'arguments'); } return $result; @@ -100,7 +97,7 @@ public function __call($method, $parameters) // we'll assume that we want to call a query macro (e.g. withTrashed) that only // exists on related models. We will just store the call and replay it later. catch (BadMethodCallException $e) { - $this->macroBuffer[] = compact('method', 'parameters'); + $this->macroBuffer[] = compact('name', 'arguments'); return $this; } diff --git a/src/Model/Relations/Relation.php b/src/Model/Relations/Relation.php index 16ff7a8..5fac89d 100755 --- a/src/Model/Relations/Relation.php +++ b/src/Model/Relations/Relation.php @@ -84,17 +84,14 @@ public function __construct(Builder $query, Model $parent) /** * Handle dynamic method calls to the relationship. - * - * @param string $method - * @param array $parameters */ - public function __call($method, $parameters) + public function __call(string $name, array $arguments): mixed { - if (static::hasMacro($method)) { - return $this->macroCall($method, $parameters); + if (static::hasMacro($name)) { + return $this->macroCall($name, $arguments); } - $result = $this->forwardCallTo($this->query, $method, $parameters); + $result = $this->forwardCallTo($this->query, $name, $arguments); if ($result === $this->query) { return $this; diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 6e61138..890a5f8 100755 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -124,10 +124,8 @@ class Builder /** * The table joins for the query. - * - * @var array */ - public $joins; + public ?array $joins = null; /** * The where constraints for the query. @@ -267,20 +265,19 @@ public function __construct( /** * Handle dynamic method calls into the method. * - * @param string $method - * @param array $parameters * @throws BadMethodCallException */ - public function __call($method, $parameters) + public function __call(string $name, array $arguments): mixed { - if (static::hasMacro($method)) { - return $this->macroCall($method, $parameters); + if (static::hasMacro($name)) { + return $this->macroCall($name, $arguments); } - if (Str::startsWith($method, 'where')) { - return $this->dynamicWhere($method, $parameters); + if (Str::startsWith($name, 'where')) { + return $this->dynamicWhere($name, $arguments); } - static::throwBadMethodCallException($method); + static::throwBadMethodCallException($name); + return null; } /** @@ -1274,7 +1271,7 @@ public function orWhereYear($column, $operator, $value = null) * Add a nested where statement to the query. * * @param string $boolean - * @return Builder|static + * @return static */ public function whereNested(Closure $callback, $boolean = 'and') { @@ -2137,11 +2134,14 @@ public function take($value) public function limit($value) { $property = $this->unions ? 'unionLimit' : 'limit'; + $value = (int) $value; - if ($value >= 0) { - $this->{$property} = $value; + if ($value < 0) { + throw new InvalidArgumentException('Limit cannot be negative.'); } + $this->{$property} = $value; + return $this; } diff --git a/src/Schema/Blueprint.php b/src/Schema/Blueprint.php index cb54c3b..40477f3 100755 --- a/src/Schema/Blueprint.php +++ b/src/Schema/Blueprint.php @@ -1000,7 +1000,7 @@ public function datetimes($precision = 0) } /** - * Add a "deleted at" timestamp for the table. + * Add a "deleted at" dateTime for the table. * * @param string $column * @param int $precision @@ -1008,11 +1008,11 @@ public function datetimes($precision = 0) */ public function softDeletes($column = 'deleted_at', $precision = 0) { - return $this->timestamp($column, $precision)->nullable(); + return $this->dateTime($column, $precision)->nullable(); } /** - * Add a "deleted at" timestampTz for the table. + * Add a "deleted at" dateTimeTz for the table. * * @param string $column * @param int $precision @@ -1020,7 +1020,7 @@ public function softDeletes($column = 'deleted_at', $precision = 0) */ public function softDeletesTz($column = 'deleted_at', $precision = 0) { - return $this->timestampTz($column, $precision)->nullable(); + return $this->dateTimeTz($column, $precision)->nullable(); } /** diff --git a/src/Schema/Schema.php b/src/Schema/Schema.php index fe301ee..d01f51a 100644 --- a/src/Schema/Schema.php +++ b/src/Schema/Schema.php @@ -60,7 +60,7 @@ public static function __callStatic($name, $arguments) return $connection->getSchemaBuilder()->{$name}(...$arguments); } - public function __call($name, $arguments) + public function __call(string $name, array $arguments): mixed { return self::__callStatic($name, $arguments); } diff --git a/tests/GenModelTest.php b/tests/GenModelTest.php index 6053585..0887b6a 100644 --- a/tests/GenModelTest.php +++ b/tests/GenModelTest.php @@ -21,7 +21,6 @@ use HyperfTest\Database\Stubs\Model\UserExtEmpty; use HyperfTest\Database\Stubs\Model\UserExtWithTrait; use Mockery; -use PhpParser\Lexer\Emulative; use PhpParser\NodeTraverser; use PhpParser\ParserFactory; use PhpParser\PrettyPrinter\Standard; @@ -71,7 +70,7 @@ public function testDatabaseFormat() } } - $astParser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7); + $astParser = (new ParserFactory())->createForNewestSupportedVersion(); $stms = $astParser->parse(file_get_contents(__DIR__ . '/Stubs/Model/UserExtEmpty.php')); $traverser = new NodeTraverser(); $visitor = new ModelUpdateVisitor(UserExtEmpty::class, $columns, ContainerStub::getModelOption()); @@ -127,7 +126,7 @@ public function testGenModelWithEnum() $columns[$i]['cast'] = 'datetime'; } } - $astParser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7); + $astParser = (new ParserFactory())->createForNewestSupportedVersion(); $stms = $astParser->parse(file_get_contents(__DIR__ . '/Stubs/Model/UserEnum.php')); $traverser = new NodeTraverser(); $visitor = new ModelUpdateVisitor(UserEnum::class, $columns, ContainerStub::getModelOption()->setForceCasts(false)); @@ -177,25 +176,18 @@ public function testGenModelWithTrait() $dispatcher->shouldReceive('dispatch')->withAnyArgs()->andReturn(null); return $dispatcher; }); - $lexer = new Emulative([ - 'usedAttributes' => [ - 'comments', - 'startLine', 'endLine', - 'startTokenPos', 'endTokenPos', - ], - ]); $connection = $container->get(ConnectionResolverInterface::class)->connection(); /** @var MySqlBuilder $builder */ $builder = $connection->getSchemaBuilder('default'); $columns = $this->formatColumns($builder->getColumnTypeListing('user_ext')); $columns = []; - $astParser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7, $lexer); + $astParser = (new ParserFactory())->createForNewestSupportedVersion(); $originStmts = $astParser->parse(file_get_contents(__DIR__ . '/Stubs/Model/UserExtWithTrait.php')); $traverser = new NodeTraverser(); $visitor = new ModelUpdateVisitor(UserExtWithTrait::class, $columns, ContainerStub::getModelOption()->setWithComments(true)->setForceCasts(false)); $traverser->addVisitor($visitor); $newStmts = $traverser->traverse($originStmts); - $code = (new Standard())->printFormatPreserving($newStmts, $originStmts, $lexer->getTokens()); + $code = (new Standard())->printFormatPreserving($newStmts, $originStmts, $astParser->getTokens()); $this->assertTrue(str_contains($code, '@property-read string $count_string')); $this->assertTrue(str_contains($code, '@property-read null|User $user')); } diff --git a/tests/ModelGenerateTest.php b/tests/ModelGenerateTest.php index 6ff4127..6628e10 100644 --- a/tests/ModelGenerateTest.php +++ b/tests/ModelGenerateTest.php @@ -30,14 +30,8 @@ class ModelGenerateTest extends TestCase { public function setUp(): void { - $this->lexer = new Emulative([ - 'usedAttributes' => [ - 'comments', - 'startLine', 'endLine', - 'startTokenPos', 'endTokenPos', - ], - ]); - $this->astParser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7, $this->lexer); + $this->lexer = new Emulative(); + $this->astParser = (new ParserFactory())->createForNewestSupportedVersion(); $this->printer = new Standard(); } diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index ed310f6..7453013 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -13,6 +13,7 @@ namespace HyperfTest\Database; use BadMethodCallException; +use Exception; use Hyperf\Collection\Collection; use Hyperf\Context\ApplicationContext; use Hyperf\Context\Context; @@ -1007,9 +1008,14 @@ public function testLimitsAndOffsets() $builder->select('*')->from('users')->skip(0)->take(0); $this->assertEquals('select * from "users" limit 0 offset 0', $builder->toSql()); - $builder = $this->getBuilder(); - $builder->select('*')->from('users')->skip(-5)->take(-10); - $this->assertEquals('select * from "users" offset 0', $builder->toSql()); + try { + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->skip(-5)->take(-10); + // $this->assertEquals('select * from "users" offset 0', $builder->toSql()); + } catch (Exception $e) { + $this->assertInstanceOf(InvalidArgumentException::class, $e); + $this->assertStringContainsString('Limit cannot be negative.', $e->getMessage()); + } } public function testForPage() diff --git a/types/Model/Builder.php b/types/Model/Builder.php index 02b16b7..24bb90d 100644 --- a/types/Model/Builder.php +++ b/types/Model/Builder.php @@ -48,11 +48,11 @@ function test( assertType('Hyperf\Database\Model\Collection', $query->findOr([1], callback: fn () => 42)); assertType('Hyperf\Types\Builder\User', $query->findOrFail(1)); assertType('Hyperf\Types\Builder\User|null', $query->find(1)); - assertType('Hyperf\Types\Builder\User|int', $query->findOr(1, fn () => 42)); - assertType('Hyperf\Types\Builder\User|int', $query->findOr(1, callback: fn () => 42)); + assertType('42|Hyperf\Types\Builder\User', $query->findOr(1, fn () => 42)); + assertType('42|Hyperf\Types\Builder\User', $query->findOr(1, callback: fn () => 42)); assertType('Hyperf\Types\Builder\User|null', $query->first()); - assertType('Hyperf\Types\Builder\User|int', $query->firstOr(fn () => 42)); - assertType('Hyperf\Types\Builder\User|int', $query->firstOr(callback: fn () => 42)); + assertType('42|Hyperf\Types\Builder\User', $query->firstOr(fn () => 42)); + assertType('42|Hyperf\Types\Builder\User', $query->firstOr(callback: fn () => 42)); assertType('Hyperf\Types\Builder\User', $query->firstOrNew(['id' => 1])); assertType('Hyperf\Types\Builder\User', $query->findOrNew(1)); assertType('Hyperf\Types\Builder\User', $query->firstOrCreate(['id' => 1])); diff --git a/types/Model/Collection.php b/types/Model/Collection.php index 8716589..f96af31 100644 --- a/types/Model/Collection.php +++ b/types/Model/Collection.php @@ -15,7 +15,7 @@ assertType('Hyperf\Database\Model\Collection', $collection); assertType('User|null', $collection->find(1)); -assertType('string|User', $collection->find(1, 'string')); +assertType('\'string\'|User', $collection->find(1, 'string')); assertType('Hyperf\Database\Model\Collection', $collection->find([1])); assertType('Hyperf\Database\Model\Collection', $collection->load('string'));