From b7091664d8b8079d310b5604ec7e2a3389d8fa1d Mon Sep 17 00:00:00 2001 From: Hans van Luttikhuizen-Ross Date: Wed, 6 Apr 2022 11:29:53 +0200 Subject: [PATCH 01/10] Add support for protected Attribute accessors --- src/Console/ModelsCommand.php | 103 ++++++++++-------- .../Attributes/Models/Simple.php | 4 +- .../__snapshots__/Test__test__1.php | 4 +- 3 files changed, 59 insertions(+), 52 deletions(-) diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index 64ee0776b..035fcf4e6 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -569,76 +569,83 @@ public function getPropertiesFromTable($model) */ public function getPropertiesFromMethods($model) { - $methods = get_class_methods($model); - if ($methods) { - sort($methods); - foreach ($methods as $method) { - $reflection = new \ReflectionMethod($model, $method); - $type = $this->getReturnTypeFromReflection($reflection); + $reflectionClass = new ReflectionClass($model); + $methodReflections = $reflectionClass->getMethods(); + if ($methodReflections) { + $methodReflections = array_filter($methodReflections, function ($methodReflection) { + return !( + $methodReflection->getDeclaringClass()->getName() === \Illuminate\Database\Eloquent\Model::class && ( + $methodReflection->getName() === 'setClassCastableAttribute' || + $methodReflection->getName() === 'setEnumCastableAttribute' + ) + ); + }); + sort($methodReflections); + foreach ($methodReflections as $methodReflection) { + $type = $this->getReturnTypeFromReflection($methodReflection); $isAttribute = is_a($type, '\Illuminate\Database\Eloquent\Casts\Attribute', true); if ( - Str::startsWith($method, 'get') && Str::endsWith( - $method, + Str::startsWith($methodReflection->getName(), 'get') && Str::endsWith( + $methodReflection->getName(), 'Attribute' - ) && $method !== 'getAttribute' + ) && $methodReflection->getName() !== 'getAttribute' ) { //Magic getAttribute - $name = Str::snake(substr($method, 3, -9)); + $name = Str::snake(substr($methodReflection->getName(), 3, -9)); if (!empty($name)) { - $type = $this->getReturnType($reflection); + $type = $this->getReturnType($methodReflection); $type = $this->getTypeInModel($model, $type); - $comment = $this->getCommentFromDocBlock($reflection); + $comment = $this->getCommentFromDocBlock($methodReflection); $this->setProperty($name, $type, true, null, $comment); } } elseif ($isAttribute) { - $name = Str::snake($method); - $types = $this->getAttributeReturnType($model, $method); + $name = Str::snake($methodReflection->getName()); + $types = $this->getAttributeReturnType($model, $methodReflection); + $comment = $this->getCommentFromDocBlock($methodReflection); if ($types->has('get')) { $type = $this->getTypeInModel($model, $types['get']); - $comment = $this->getCommentFromDocBlock($reflection); $this->setProperty($name, $type, true, null, $comment); } if ($types->has('set')) { - $comment = $this->getCommentFromDocBlock($reflection); $this->setProperty($name, null, null, true, $comment); } } elseif ( - Str::startsWith($method, 'set') && Str::endsWith( - $method, + Str::startsWith($methodReflection->getName(), 'set') && Str::endsWith( + $methodReflection->getName(), 'Attribute' - ) && $method !== 'setAttribute' + ) && $methodReflection->getName() !== 'setAttribute' ) { //Magic setAttribute - $name = Str::snake(substr($method, 3, -9)); + $name = Str::snake(substr($methodReflection->getName(), 3, -9)); if (!empty($name)) { - $comment = $this->getCommentFromDocBlock($reflection); + $comment = $this->getCommentFromDocBlock($methodReflection); $this->setProperty($name, null, null, true, $comment); } - } elseif (Str::startsWith($method, 'scope') && $method !== 'scopeQuery') { + } elseif (Str::startsWith($methodReflection->getName(), 'scope') && $methodReflection->getName() !== 'scopeQuery') { //Magic setAttribute - $name = Str::camel(substr($method, 5)); + $name = Str::camel(substr($methodReflection->getName(), 5)); if (!empty($name)) { - $comment = $this->getCommentFromDocBlock($reflection); - $args = $this->getParameters($reflection); + $comment = $this->getCommentFromDocBlock($methodReflection); + $args = $this->getParameters($methodReflection); //Remove the first ($query) argument array_shift($args); $builder = $this->getClassNameInDestinationFile( - $reflection->getDeclaringClass(), + $methodReflection->getDeclaringClass(), get_class($model->newModelQuery()) ); $modelName = $this->getClassNameInDestinationFile( - $reflection->getDeclaringClass(), - $reflection->getDeclaringClass()->getName() + $methodReflection->getDeclaringClass(), + $methodReflection->getDeclaringClass()->getName() ); $this->setMethod($name, $builder . '|' . $modelName, $args, $comment); } - } elseif (in_array($method, ['query', 'newQuery', 'newModelQuery'])) { + } elseif (in_array($methodReflection->getName(), ['query', 'newQuery', 'newModelQuery'])) { $builder = $this->getClassNameInDestinationFile($model, get_class($model->newModelQuery())); $this->setMethod( - $method, + $methodReflection->getName(), $builder . '|' . $this->getClassNameInDestinationFile($model, get_class($model)) ); @@ -646,24 +653,24 @@ public function getPropertiesFromMethods($model) $this->writeModelExternalBuilderMethods($model); } } elseif ( - !method_exists('Illuminate\Database\Eloquent\Model', $method) - && !Str::startsWith($method, 'get') + !method_exists('Illuminate\Database\Eloquent\Model', $methodReflection->getName()) + && !Str::startsWith($methodReflection->getName(), 'get') ) { //Use reflection to inspect the code, based on Illuminate/Support/SerializableClosure.php - if ($returnType = $reflection->getReturnType()) { + if ($returnType = $methodReflection->getReturnType()) { $type = $returnType instanceof ReflectionNamedType ? $returnType->getName() : (string)$returnType; } else { // php 7.x type or fallback to docblock - $type = (string)$this->getReturnTypeFromDocBlock($reflection); + $type = (string)$this->getReturnTypeFromDocBlock($methodReflection); } - $file = new \SplFileObject($reflection->getFileName()); - $file->seek($reflection->getStartLine() - 1); + $file = new \SplFileObject($methodReflection->getFileName()); + $file->seek($methodReflection->getStartLine() - 1); $code = ''; - while ($file->key() < $reflection->getEndLine()) { + while ($file->key() < $methodReflection->getEndLine()) { $code .= $file->current(); $file->next(); } @@ -677,20 +684,20 @@ public function getPropertiesFromMethods($model) $search = '$this->' . $relation . '('; if (stripos($code, $search) || ltrim($impl, '\\') === ltrim((string)$type, '\\')) { //Resolve the relation's model to a Relation object. - $methodReflection = new \ReflectionMethod($model, $method); if ($methodReflection->getNumberOfParameters()) { continue; } - $comment = $this->getCommentFromDocBlock($reflection); + $comment = $this->getCommentFromDocBlock($methodReflection); // Adding constraints requires reading model properties which // can cause errors. Since we don't need constraints we can // disable them when we fetch the relation to avoid errors. - $relationObj = Relation::noConstraints(function () use ($model, $method) { + $relationObj = Relation::noConstraints(function () use ($model, $methodReflection) { try { - return $model->$method(); + $methodName = $methodReflection->getName(); + return $model->$methodName(); } catch (Throwable $e) { - $this->warn(sprintf('Error resolving relation model of %s:%s() : %s', get_class($model), $method, $e->getMessage())); + $this->warn(sprintf('Error resolving relation model of %s:%s() : %s', get_class($model), $methodReflection->getName(), $e->getMessage())); return null; } @@ -715,7 +722,7 @@ public function getPropertiesFromMethods($model) ); $collectionTypeHint = $this->getCollectionTypeHint($collectionClassNameInModel, $relatedModel); $this->setProperty( - $method, + $methodReflection->getName(), $collectionTypeHint, true, null, @@ -723,7 +730,7 @@ public function getPropertiesFromMethods($model) ); if ($this->write_model_relation_count_properties) { $this->setProperty( - Str::snake($method) . '_count', + Str::snake($methodReflection->getName()) . '_count', 'int|null', true, false @@ -736,7 +743,7 @@ public function getPropertiesFromMethods($model) ) { // Model isn't specified because relation is polymorphic $this->setProperty( - $method, + $methodReflection->getName(), $this->getClassNameInDestinationFile($model, Model::class) . '|\Eloquent', true, null, @@ -745,7 +752,7 @@ public function getPropertiesFromMethods($model) } else { //Single model is returned $this->setProperty( - $method, + $methodReflection->getName(), $relatedModel, true, null, @@ -1123,10 +1130,10 @@ protected function hasCamelCaseModelProperties() return $this->laravel['config']->get('ide-helper.model_camel_case_properties', false); } - protected function getAttributeReturnType(Model $model, string $method): Collection + protected function getAttributeReturnType(Model $model, \ReflectionMethod $reflectionMethod): Collection { /** @var Attribute $attribute */ - $attribute = $model->{$method}(); + $attribute = $reflectionMethod->invoke($model); return collect([ 'get' => $attribute->get ? optional(new \ReflectionFunction($attribute->get))->getReturnType() : null, diff --git a/tests/Console/ModelsCommand/Attributes/Models/Simple.php b/tests/Console/ModelsCommand/Attributes/Models/Simple.php index 0d1eff89e..f64861b44 100644 --- a/tests/Console/ModelsCommand/Attributes/Models/Simple.php +++ b/tests/Console/ModelsCommand/Attributes/Models/Simple.php @@ -9,7 +9,7 @@ class Simple extends Model { - public function name(): Attribute + protected function name(): Attribute { return new Attribute( function (?string $name): ?string { @@ -29,7 +29,7 @@ function (?string $name): ?string { * * @return \Illuminate\Database\Eloquent\Casts\Attribute */ - public function notAnAttribute() + protected function notAnAttribute() { return new Attribute( function (?string $value): ?string { diff --git a/tests/Console/ModelsCommand/Attributes/__snapshots__/Test__test__1.php b/tests/Console/ModelsCommand/Attributes/__snapshots__/Test__test__1.php index eabeffcbb..df6863950 100644 --- a/tests/Console/ModelsCommand/Attributes/__snapshots__/Test__test__1.php +++ b/tests/Console/ModelsCommand/Attributes/__snapshots__/Test__test__1.php @@ -20,7 +20,7 @@ */ class Simple extends Model { - public function name(): Attribute + protected function name(): Attribute { return new Attribute( function (?string $name): ?string { @@ -40,7 +40,7 @@ function (?string $name): ?string { * * @return \Illuminate\Database\Eloquent\Casts\Attribute */ - public function notAnAttribute() + protected function notAnAttribute() { return new Attribute( function (?string $value): ?string { From 3de36b99c7ff55e9eab07882484fcfdc83e967e3 Mon Sep 17 00:00:00 2001 From: Hans van Luttikhuizen-Ross Date: Wed, 6 Apr 2022 11:31:50 +0200 Subject: [PATCH 02/10] Fix formatting --- src/Console/ModelsCommand.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index 035fcf4e6..c46775178 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -1142,7 +1142,7 @@ protected function getAttributeReturnType(Model $model, \ReflectionMethod $refle ->filter() ->map(function ($type) { if ($type instanceof \ReflectionUnionType) { - $types =collect($type->getTypes()) + $types = collect($type->getTypes()) /** @var ReflectionType $reflectionType */ ->map(function ($reflectionType) { return collect($this->extractReflectionTypes($reflectionType)); @@ -1230,7 +1230,7 @@ protected function getReturnTypeFromReflection(\ReflectionMethod $reflection): ? $type = implode('|', $types); if ($returnType->allowsNull()) { - $type .='|null'; + $type .= '|null'; } return $type; @@ -1472,10 +1472,10 @@ protected function getParamType(\ReflectionMethod $method, \ReflectionParameter $type = implode('|', $types); if ($paramType->allowsNull()) { - if (count($types)==1) { + if (count($types) == 1) { $type = '?' . $type; } else { - $type .='|null'; + $type .= '|null'; } } @@ -1552,7 +1552,7 @@ protected function extractReflectionTypes(ReflectionType $reflection_type) } else { $types = []; foreach ($reflection_type->getTypes() as $named_type) { - if ($named_type->getName()==='null') { + if ($named_type->getName() === 'null') { continue; } From fab3e706354fae18b508a0ed9a1e610e6e03654a Mon Sep 17 00:00:00 2001 From: Hans van Luttikhuizen-Ross Date: Wed, 6 Apr 2022 11:57:19 +0200 Subject: [PATCH 03/10] Prevent accessors methods marked as private from being added --- src/Console/ModelsCommand.php | 2 +- tests/Console/ModelsCommand/Getter/Models/Simple.php | 4 ++++ .../ModelsCommand/Getter/__snapshots__/Test__test__1.php | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index c46775178..6572fa93d 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -573,7 +573,7 @@ public function getPropertiesFromMethods($model) $methodReflections = $reflectionClass->getMethods(); if ($methodReflections) { $methodReflections = array_filter($methodReflections, function ($methodReflection) { - return !( + return !$methodReflection->isPrivate() && !( $methodReflection->getDeclaringClass()->getName() === \Illuminate\Database\Eloquent\Model::class && ( $methodReflection->getName() === 'setClassCastableAttribute' || $methodReflection->getName() === 'setEnumCastableAttribute' diff --git a/tests/Console/ModelsCommand/Getter/Models/Simple.php b/tests/Console/ModelsCommand/Getter/Models/Simple.php index dba42eb12..639ecfc5f 100644 --- a/tests/Console/ModelsCommand/Getter/Models/Simple.php +++ b/tests/Console/ModelsCommand/Getter/Models/Simple.php @@ -103,4 +103,8 @@ public function getAttributeReturnsNullableCallableAttribute(): ?callable public function getAttributeReturnsVoidAttribute(): void { } + + private function getInvalidAccessModifierAttribute() + { + } } diff --git a/tests/Console/ModelsCommand/Getter/__snapshots__/Test__test__1.php b/tests/Console/ModelsCommand/Getter/__snapshots__/Test__test__1.php index ab67d5444..94b0a3eb3 100644 --- a/tests/Console/ModelsCommand/Getter/__snapshots__/Test__test__1.php +++ b/tests/Console/ModelsCommand/Getter/__snapshots__/Test__test__1.php @@ -133,4 +133,8 @@ public function getAttributeReturnsNullableCallableAttribute(): ?callable public function getAttributeReturnsVoidAttribute(): void { } + + private function getInvalidAccessModifierAttribute() + { + } } From a27a1d3d89fcf1d631af684470b467dab02fa8f8 Mon Sep 17 00:00:00 2001 From: Hans van Luttikhuizen-Ross Date: Wed, 6 Apr 2022 12:10:09 +0200 Subject: [PATCH 04/10] Exclude specific accessors based on trait instead of class --- src/Console/ModelsCommand.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index 6572fa93d..e09ee6559 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -574,7 +574,10 @@ public function getPropertiesFromMethods($model) if ($methodReflections) { $methodReflections = array_filter($methodReflections, function ($methodReflection) { return !$methodReflection->isPrivate() && !( - $methodReflection->getDeclaringClass()->getName() === \Illuminate\Database\Eloquent\Model::class && ( + in_array( + \Illuminate\Database\Eloquent\Concerns\HasAttributes::class, + $methodReflection->getDeclaringClass()->getTraitNames() + ) && ( $methodReflection->getName() === 'setClassCastableAttribute' || $methodReflection->getName() === 'setEnumCastableAttribute' ) From 94c05b21f041890faf74f3aebe3421fafb48bce1 Mon Sep 17 00:00:00 2001 From: Hans van Luttikhuizen-Ross Date: Wed, 6 Apr 2022 12:15:51 +0200 Subject: [PATCH 05/10] Add changelog entry --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef0c1a05f..743581d39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,13 @@ All notable changes to this project will be documented in this file. [Next release](https://github.com/barryvdh/laravel-ide-helper/compare/v2.13.0...master) -------------- +### Fixed +- Add support for attribute accessors marked as protected. [#1339 / pindab0ter](https://github.com/barryvdh/laravel-ide-helper/pull/1339) + 2023-02-04, 2.13.0 ------------------ -### Fixes +### Fixed - Fix return type of methods provided by `SoftDeletes` [#1345 / KentarouTakeda](https://github.com/barryvdh/laravel-ide-helper/pull/1345) - Handle PHP 8.1 deprecation warnings when passing `null` to `new \ReflectionClass` [#1351 / mfn](https://github.com/barryvdh/laravel-ide-helper/pull/1351) - Fix issue where \Eloquent is not included when using write_mixin [#1352 / Jefemy](https://github.com/barryvdh/laravel-ide-helper/pull/1352) From f119ba614c38b257c749b4265c6be6a368d432d2 Mon Sep 17 00:00:00 2001 From: Hans van Luttikhuizen-Ross Date: Thu, 7 Apr 2022 11:54:04 +0200 Subject: [PATCH 06/10] Add clarifying comment --- src/Console/ModelsCommand.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index e09ee6559..7d27166d8 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -572,7 +572,9 @@ public function getPropertiesFromMethods($model) $reflectionClass = new ReflectionClass($model); $methodReflections = $reflectionClass->getMethods(); if ($methodReflections) { - $methodReflections = array_filter($methodReflections, function ($methodReflection) { + // Filter out private methods because they can't be used to generate magic properties and HasAttributes' + // methods that resemble mutators but aren't. + $methodReflections = array_filter($methodReflections, function (\ReflectionMethod $methodReflection) { return !$methodReflection->isPrivate() && !( in_array( \Illuminate\Database\Eloquent\Concerns\HasAttributes::class, From 80d886479d6aa690b693aa5a91acf67fa1c39b17 Mon Sep 17 00:00:00 2001 From: Hans van Luttikhuizen-Ross Date: Thu, 7 Apr 2022 15:52:49 +0200 Subject: [PATCH 07/10] Fix accessor attributes not working on PHP < 8.1 --- src/Console/ModelsCommand.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index 7d27166d8..71d6c6d8c 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -1137,6 +1137,9 @@ protected function hasCamelCaseModelProperties() protected function getAttributeReturnType(Model $model, \ReflectionMethod $reflectionMethod): Collection { + // Private/protected ReflectionMethods require setAccessible prior to PHP 8.1 + $reflectionMethod->setAccessible(true); + /** @var Attribute $attribute */ $attribute = $reflectionMethod->invoke($model); From 3f923d490e7d49bd1886edbae9249fdb2a369213 Mon Sep 17 00:00:00 2001 From: Hans van Luttikhuizen-Ross Date: Sat, 18 Feb 2023 23:34:13 +0100 Subject: [PATCH 08/10] Reintroduce method variable to reduce PR clutter --- src/Console/ModelsCommand.php | 39 ++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index 71d6c6d8c..7b7b763d6 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -589,14 +589,15 @@ public function getPropertiesFromMethods($model) foreach ($methodReflections as $methodReflection) { $type = $this->getReturnTypeFromReflection($methodReflection); $isAttribute = is_a($type, '\Illuminate\Database\Eloquent\Casts\Attribute', true); + $method = $methodReflection->getName(); if ( - Str::startsWith($methodReflection->getName(), 'get') && Str::endsWith( - $methodReflection->getName(), + Str::startsWith($method, 'get') && Str::endsWith( + $method, 'Attribute' - ) && $methodReflection->getName() !== 'getAttribute' + ) && $method !== 'getAttribute' ) { //Magic getAttribute - $name = Str::snake(substr($methodReflection->getName(), 3, -9)); + $name = Str::snake(substr($method, 3, -9)); if (!empty($name)) { $type = $this->getReturnType($methodReflection); $type = $this->getTypeInModel($model, $type); @@ -604,7 +605,7 @@ public function getPropertiesFromMethods($model) $this->setProperty($name, $type, true, null, $comment); } } elseif ($isAttribute) { - $name = Str::snake($methodReflection->getName()); + $name = Str::snake($method); $types = $this->getAttributeReturnType($model, $methodReflection); $comment = $this->getCommentFromDocBlock($methodReflection); @@ -617,20 +618,20 @@ public function getPropertiesFromMethods($model) $this->setProperty($name, null, null, true, $comment); } } elseif ( - Str::startsWith($methodReflection->getName(), 'set') && Str::endsWith( - $methodReflection->getName(), + Str::startsWith($method, 'set') && Str::endsWith( + $method, 'Attribute' - ) && $methodReflection->getName() !== 'setAttribute' + ) && $method !== 'setAttribute' ) { //Magic setAttribute - $name = Str::snake(substr($methodReflection->getName(), 3, -9)); + $name = Str::snake(substr($method, 3, -9)); if (!empty($name)) { $comment = $this->getCommentFromDocBlock($methodReflection); $this->setProperty($name, null, null, true, $comment); } - } elseif (Str::startsWith($methodReflection->getName(), 'scope') && $methodReflection->getName() !== 'scopeQuery') { + } elseif (Str::startsWith($method, 'scope') && $method !== 'scopeQuery') { //Magic setAttribute - $name = Str::camel(substr($methodReflection->getName(), 5)); + $name = Str::camel(substr($method, 5)); if (!empty($name)) { $comment = $this->getCommentFromDocBlock($methodReflection); $args = $this->getParameters($methodReflection); @@ -646,11 +647,11 @@ public function getPropertiesFromMethods($model) ); $this->setMethod($name, $builder . '|' . $modelName, $args, $comment); } - } elseif (in_array($methodReflection->getName(), ['query', 'newQuery', 'newModelQuery'])) { + } elseif (in_array($method, ['query', 'newQuery', 'newModelQuery'])) { $builder = $this->getClassNameInDestinationFile($model, get_class($model->newModelQuery())); $this->setMethod( - $methodReflection->getName(), + $method, $builder . '|' . $this->getClassNameInDestinationFile($model, get_class($model)) ); @@ -658,8 +659,8 @@ public function getPropertiesFromMethods($model) $this->writeModelExternalBuilderMethods($model); } } elseif ( - !method_exists('Illuminate\Database\Eloquent\Model', $methodReflection->getName()) - && !Str::startsWith($methodReflection->getName(), 'get') + !method_exists('Illuminate\Database\Eloquent\Model', $method) + && !Str::startsWith($method, 'get') ) { //Use reflection to inspect the code, based on Illuminate/Support/SerializableClosure.php if ($returnType = $methodReflection->getReturnType()) { @@ -727,7 +728,7 @@ public function getPropertiesFromMethods($model) ); $collectionTypeHint = $this->getCollectionTypeHint($collectionClassNameInModel, $relatedModel); $this->setProperty( - $methodReflection->getName(), + $method, $collectionTypeHint, true, null, @@ -735,7 +736,7 @@ public function getPropertiesFromMethods($model) ); if ($this->write_model_relation_count_properties) { $this->setProperty( - Str::snake($methodReflection->getName()) . '_count', + Str::snake($method) . '_count', 'int|null', true, false @@ -748,7 +749,7 @@ public function getPropertiesFromMethods($model) ) { // Model isn't specified because relation is polymorphic $this->setProperty( - $methodReflection->getName(), + $method, $this->getClassNameInDestinationFile($model, Model::class) . '|\Eloquent', true, null, @@ -757,7 +758,7 @@ public function getPropertiesFromMethods($model) } else { //Single model is returned $this->setProperty( - $methodReflection->getName(), + $method, $relatedModel, true, null, From 2e996b6f648847d7e3f66bf6570a01949d91f1aa Mon Sep 17 00:00:00 2001 From: Hans van Luttikhuizen-Ross Date: Sat, 18 Feb 2023 23:36:32 +0100 Subject: [PATCH 09/10] Change variable name to reduce PR clutter --- src/Console/ModelsCommand.php | 54 +++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index 7b7b763d6..d3d2ab969 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -570,11 +570,11 @@ public function getPropertiesFromTable($model) public function getPropertiesFromMethods($model) { $reflectionClass = new ReflectionClass($model); - $methodReflections = $reflectionClass->getMethods(); - if ($methodReflections) { + $reflections = $reflectionClass->getMethods(); + if ($reflections) { // Filter out private methods because they can't be used to generate magic properties and HasAttributes' // methods that resemble mutators but aren't. - $methodReflections = array_filter($methodReflections, function (\ReflectionMethod $methodReflection) { + $reflections = array_filter($reflections, function (\ReflectionMethod $methodReflection) { return !$methodReflection->isPrivate() && !( in_array( \Illuminate\Database\Eloquent\Concerns\HasAttributes::class, @@ -585,11 +585,11 @@ public function getPropertiesFromMethods($model) ) ); }); - sort($methodReflections); - foreach ($methodReflections as $methodReflection) { - $type = $this->getReturnTypeFromReflection($methodReflection); + sort($reflections); + foreach ($reflections as $reflection) { + $type = $this->getReturnTypeFromReflection($reflection); $isAttribute = is_a($type, '\Illuminate\Database\Eloquent\Casts\Attribute', true); - $method = $methodReflection->getName(); + $method = $reflection->getName(); if ( Str::startsWith($method, 'get') && Str::endsWith( $method, @@ -599,15 +599,15 @@ public function getPropertiesFromMethods($model) //Magic getAttribute $name = Str::snake(substr($method, 3, -9)); if (!empty($name)) { - $type = $this->getReturnType($methodReflection); + $type = $this->getReturnType($reflection); $type = $this->getTypeInModel($model, $type); - $comment = $this->getCommentFromDocBlock($methodReflection); + $comment = $this->getCommentFromDocBlock($reflection); $this->setProperty($name, $type, true, null, $comment); } } elseif ($isAttribute) { $name = Str::snake($method); - $types = $this->getAttributeReturnType($model, $methodReflection); - $comment = $this->getCommentFromDocBlock($methodReflection); + $types = $this->getAttributeReturnType($model, $reflection); + $comment = $this->getCommentFromDocBlock($reflection); if ($types->has('get')) { $type = $this->getTypeInModel($model, $types['get']); @@ -626,24 +626,24 @@ public function getPropertiesFromMethods($model) //Magic setAttribute $name = Str::snake(substr($method, 3, -9)); if (!empty($name)) { - $comment = $this->getCommentFromDocBlock($methodReflection); + $comment = $this->getCommentFromDocBlock($reflection); $this->setProperty($name, null, null, true, $comment); } } elseif (Str::startsWith($method, 'scope') && $method !== 'scopeQuery') { //Magic setAttribute $name = Str::camel(substr($method, 5)); if (!empty($name)) { - $comment = $this->getCommentFromDocBlock($methodReflection); - $args = $this->getParameters($methodReflection); + $comment = $this->getCommentFromDocBlock($reflection); + $args = $this->getParameters($reflection); //Remove the first ($query) argument array_shift($args); $builder = $this->getClassNameInDestinationFile( - $methodReflection->getDeclaringClass(), + $reflection->getDeclaringClass(), get_class($model->newModelQuery()) ); $modelName = $this->getClassNameInDestinationFile( - $methodReflection->getDeclaringClass(), - $methodReflection->getDeclaringClass()->getName() + $reflection->getDeclaringClass(), + $reflection->getDeclaringClass()->getName() ); $this->setMethod($name, $builder . '|' . $modelName, $args, $comment); } @@ -663,20 +663,20 @@ public function getPropertiesFromMethods($model) && !Str::startsWith($method, 'get') ) { //Use reflection to inspect the code, based on Illuminate/Support/SerializableClosure.php - if ($returnType = $methodReflection->getReturnType()) { + if ($returnType = $reflection->getReturnType()) { $type = $returnType instanceof ReflectionNamedType ? $returnType->getName() : (string)$returnType; } else { // php 7.x type or fallback to docblock - $type = (string)$this->getReturnTypeFromDocBlock($methodReflection); + $type = (string)$this->getReturnTypeFromDocBlock($reflection); } - $file = new \SplFileObject($methodReflection->getFileName()); - $file->seek($methodReflection->getStartLine() - 1); + $file = new \SplFileObject($reflection->getFileName()); + $file->seek($reflection->getStartLine() - 1); $code = ''; - while ($file->key() < $methodReflection->getEndLine()) { + while ($file->key() < $reflection->getEndLine()) { $code .= $file->current(); $file->next(); } @@ -690,20 +690,20 @@ public function getPropertiesFromMethods($model) $search = '$this->' . $relation . '('; if (stripos($code, $search) || ltrim($impl, '\\') === ltrim((string)$type, '\\')) { //Resolve the relation's model to a Relation object. - if ($methodReflection->getNumberOfParameters()) { + if ($reflection->getNumberOfParameters()) { continue; } - $comment = $this->getCommentFromDocBlock($methodReflection); + $comment = $this->getCommentFromDocBlock($reflection); // Adding constraints requires reading model properties which // can cause errors. Since we don't need constraints we can // disable them when we fetch the relation to avoid errors. - $relationObj = Relation::noConstraints(function () use ($model, $methodReflection) { + $relationObj = Relation::noConstraints(function () use ($model, $reflection) { try { - $methodName = $methodReflection->getName(); + $methodName = $reflection->getName(); return $model->$methodName(); } catch (Throwable $e) { - $this->warn(sprintf('Error resolving relation model of %s:%s() : %s', get_class($model), $methodReflection->getName(), $e->getMessage())); + $this->warn(sprintf('Error resolving relation model of %s:%s() : %s', get_class($model), $reflection->getName(), $e->getMessage())); return null; } From 917b06ef76b1e1a57cb1d0da30ad95a37bae2b29 Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Mon, 20 Feb 2023 09:39:39 +0100 Subject: [PATCH 10/10] Update CHANGELOG.md --- CHANGELOG.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34bf312d6..503f08992 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,9 +29,6 @@ All notable changes to this project will be documented in this file. - Add support for custom casts that implement `CastsInboundAttributes` [#1329 / sforward](https://github.com/barryvdh/laravel-ide-helper/pull/1329) - Add option `use_generics_annotations` for collection type hints [#1298 / tanerkay](https://github.com/barryvdh/laravel-ide-helper/pull/1298) -### Changed -- Refactor resolving of null information for custom casted attribute types [#1330 / wimski](https://github.com/barryvdh/laravel-ide-helper/pull/1330) - 2022-03-06, 2.12.3 ------------------