mirror of
https://github.com/barryvdh/laravel-ide-helper.git
synced 2026-08-17 17:47:13 +00:00
Add support for protected Attribute accessors (#1339)
* Add support for protected Attribute accessors * Fix formatting * Prevent accessors methods marked as private from being added * Exclude specific accessors based on trait instead of class * Add changelog entry * Add clarifying comment * Fix accessor attributes not working on PHP < 8.1 * Reintroduce method variable to reduce PR clutter * Change variable name to reduce PR clutter * Update CHANGELOG.md --------- Co-authored-by: Barry vd. Heuvel <[email protected]> Co-authored-by: Barry vd. Heuvel <[email protected]>
This commit is contained in:
co-authored by
Barry vd. Heuvel
Barry vd. Heuvel
parent
aa1aa66ee6
commit
39885645b9
+5
-1
@@ -5,6 +5,10 @@ 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)
|
[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)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Add support for `immutable_date:*` and `immutable_datetime:*` casts. [#1380 / thekonz](https://github.com/barryvdh/laravel-ide-helper/pull/1380)
|
- Add support for `immutable_date:*` and `immutable_datetime:*` casts. [#1380 / thekonz](https://github.com/barryvdh/laravel-ide-helper/pull/1380)
|
||||||
|
|
||||||
@@ -14,7 +18,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
2023-02-04, 2.13.0
|
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)
|
- 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)
|
- 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)
|
- Fix issue where \Eloquent is not included when using write_mixin [#1352 / Jefemy](https://github.com/barryvdh/laravel-ide-helper/pull/1352)
|
||||||
|
|||||||
@@ -605,13 +605,27 @@ class ModelsCommand extends Command
|
|||||||
*/
|
*/
|
||||||
public function getPropertiesFromMethods($model)
|
public function getPropertiesFromMethods($model)
|
||||||
{
|
{
|
||||||
$methods = get_class_methods($model);
|
$reflectionClass = new ReflectionClass($model);
|
||||||
if ($methods) {
|
$reflections = $reflectionClass->getMethods();
|
||||||
sort($methods);
|
if ($reflections) {
|
||||||
foreach ($methods as $method) {
|
// Filter out private methods because they can't be used to generate magic properties and HasAttributes'
|
||||||
$reflection = new \ReflectionMethod($model, $method);
|
// methods that resemble mutators but aren't.
|
||||||
|
$reflections = array_filter($reflections, function (\ReflectionMethod $methodReflection) {
|
||||||
|
return !$methodReflection->isPrivate() && !(
|
||||||
|
in_array(
|
||||||
|
\Illuminate\Database\Eloquent\Concerns\HasAttributes::class,
|
||||||
|
$methodReflection->getDeclaringClass()->getTraitNames()
|
||||||
|
) && (
|
||||||
|
$methodReflection->getName() === 'setClassCastableAttribute' ||
|
||||||
|
$methodReflection->getName() === 'setEnumCastableAttribute'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
sort($reflections);
|
||||||
|
foreach ($reflections as $reflection) {
|
||||||
$type = $this->getReturnTypeFromReflection($reflection);
|
$type = $this->getReturnTypeFromReflection($reflection);
|
||||||
$isAttribute = is_a($type, '\Illuminate\Database\Eloquent\Casts\Attribute', true);
|
$isAttribute = is_a($type, '\Illuminate\Database\Eloquent\Casts\Attribute', true);
|
||||||
|
$method = $reflection->getName();
|
||||||
if (
|
if (
|
||||||
Str::startsWith($method, 'get') && Str::endsWith(
|
Str::startsWith($method, 'get') && Str::endsWith(
|
||||||
$method,
|
$method,
|
||||||
@@ -628,16 +642,15 @@ class ModelsCommand extends Command
|
|||||||
}
|
}
|
||||||
} elseif ($isAttribute) {
|
} elseif ($isAttribute) {
|
||||||
$name = Str::snake($method);
|
$name = Str::snake($method);
|
||||||
$types = $this->getAttributeReturnType($model, $method);
|
$types = $this->getAttributeReturnType($model, $reflection);
|
||||||
|
$comment = $this->getCommentFromDocBlock($reflection);
|
||||||
|
|
||||||
if ($types->has('get')) {
|
if ($types->has('get')) {
|
||||||
$type = $this->getTypeInModel($model, $types['get']);
|
$type = $this->getTypeInModel($model, $types['get']);
|
||||||
$comment = $this->getCommentFromDocBlock($reflection);
|
|
||||||
$this->setProperty($name, $type, true, null, $comment);
|
$this->setProperty($name, $type, true, null, $comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($types->has('set')) {
|
if ($types->has('set')) {
|
||||||
$comment = $this->getCommentFromDocBlock($reflection);
|
|
||||||
$this->setProperty($name, null, null, true, $comment);
|
$this->setProperty($name, null, null, true, $comment);
|
||||||
}
|
}
|
||||||
} elseif (
|
} elseif (
|
||||||
@@ -713,8 +726,7 @@ class ModelsCommand extends Command
|
|||||||
$search = '$this->' . $relation . '(';
|
$search = '$this->' . $relation . '(';
|
||||||
if (stripos($code, $search) || ltrim($impl, '\\') === ltrim((string)$type, '\\')) {
|
if (stripos($code, $search) || ltrim($impl, '\\') === ltrim((string)$type, '\\')) {
|
||||||
//Resolve the relation's model to a Relation object.
|
//Resolve the relation's model to a Relation object.
|
||||||
$methodReflection = new \ReflectionMethod($model, $method);
|
if ($reflection->getNumberOfParameters()) {
|
||||||
if ($methodReflection->getNumberOfParameters()) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,11 +734,12 @@ class ModelsCommand extends Command
|
|||||||
// Adding constraints requires reading model properties which
|
// Adding constraints requires reading model properties which
|
||||||
// can cause errors. Since we don't need constraints we can
|
// can cause errors. Since we don't need constraints we can
|
||||||
// disable them when we fetch the relation to avoid errors.
|
// disable them when we fetch the relation to avoid errors.
|
||||||
$relationObj = Relation::noConstraints(function () use ($model, $method) {
|
$relationObj = Relation::noConstraints(function () use ($model, $reflection) {
|
||||||
try {
|
try {
|
||||||
return $model->$method();
|
$methodName = $reflection->getName();
|
||||||
|
return $model->$methodName();
|
||||||
} catch (Throwable $e) {
|
} 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), $reflection->getName(), $e->getMessage()));
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1159,10 +1172,13 @@ class ModelsCommand extends Command
|
|||||||
return $this->laravel['config']->get('ide-helper.model_camel_case_properties', false);
|
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
|
||||||
{
|
{
|
||||||
|
// Private/protected ReflectionMethods require setAccessible prior to PHP 8.1
|
||||||
|
$reflectionMethod->setAccessible(true);
|
||||||
|
|
||||||
/** @var Attribute $attribute */
|
/** @var Attribute $attribute */
|
||||||
$attribute = $model->{$method}();
|
$attribute = $reflectionMethod->invoke($model);
|
||||||
|
|
||||||
return collect([
|
return collect([
|
||||||
'get' => $attribute->get ? optional(new \ReflectionFunction($attribute->get))->getReturnType() : null,
|
'get' => $attribute->get ? optional(new \ReflectionFunction($attribute->get))->getReturnType() : null,
|
||||||
@@ -1171,7 +1187,7 @@ class ModelsCommand extends Command
|
|||||||
->filter()
|
->filter()
|
||||||
->map(function ($type) {
|
->map(function ($type) {
|
||||||
if ($type instanceof \ReflectionUnionType) {
|
if ($type instanceof \ReflectionUnionType) {
|
||||||
$types =collect($type->getTypes())
|
$types = collect($type->getTypes())
|
||||||
/** @var ReflectionType $reflectionType */
|
/** @var ReflectionType $reflectionType */
|
||||||
->map(function ($reflectionType) {
|
->map(function ($reflectionType) {
|
||||||
return collect($this->extractReflectionTypes($reflectionType));
|
return collect($this->extractReflectionTypes($reflectionType));
|
||||||
@@ -1259,7 +1275,7 @@ class ModelsCommand extends Command
|
|||||||
$type = implode('|', $types);
|
$type = implode('|', $types);
|
||||||
|
|
||||||
if ($returnType->allowsNull()) {
|
if ($returnType->allowsNull()) {
|
||||||
$type .='|null';
|
$type .= '|null';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $type;
|
return $type;
|
||||||
@@ -1501,10 +1517,10 @@ class ModelsCommand extends Command
|
|||||||
$type = implode('|', $types);
|
$type = implode('|', $types);
|
||||||
|
|
||||||
if ($paramType->allowsNull()) {
|
if ($paramType->allowsNull()) {
|
||||||
if (count($types)==1) {
|
if (count($types) == 1) {
|
||||||
$type = '?' . $type;
|
$type = '?' . $type;
|
||||||
} else {
|
} else {
|
||||||
$type .='|null';
|
$type .= '|null';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1581,7 +1597,7 @@ class ModelsCommand extends Command
|
|||||||
} else {
|
} else {
|
||||||
$types = [];
|
$types = [];
|
||||||
foreach ($reflection_type->getTypes() as $named_type) {
|
foreach ($reflection_type->getTypes() as $named_type) {
|
||||||
if ($named_type->getName()==='null') {
|
if ($named_type->getName() === 'null') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
|
|
||||||
class Simple extends Model
|
class Simple extends Model
|
||||||
{
|
{
|
||||||
public function name(): Attribute
|
protected function name(): Attribute
|
||||||
{
|
{
|
||||||
return new Attribute(
|
return new Attribute(
|
||||||
function (?string $name): ?string {
|
function (?string $name): ?string {
|
||||||
@@ -29,7 +29,7 @@ class Simple extends Model
|
|||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Eloquent\Casts\Attribute
|
* @return \Illuminate\Database\Eloquent\Casts\Attribute
|
||||||
*/
|
*/
|
||||||
public function notAnAttribute()
|
protected function notAnAttribute()
|
||||||
{
|
{
|
||||||
return new Attribute(
|
return new Attribute(
|
||||||
function (?string $value): ?string {
|
function (?string $value): ?string {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
*/
|
*/
|
||||||
class Simple extends Model
|
class Simple extends Model
|
||||||
{
|
{
|
||||||
public function name(): Attribute
|
protected function name(): Attribute
|
||||||
{
|
{
|
||||||
return new Attribute(
|
return new Attribute(
|
||||||
function (?string $name): ?string {
|
function (?string $name): ?string {
|
||||||
@@ -40,7 +40,7 @@ class Simple extends Model
|
|||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Eloquent\Casts\Attribute
|
* @return \Illuminate\Database\Eloquent\Casts\Attribute
|
||||||
*/
|
*/
|
||||||
public function notAnAttribute()
|
protected function notAnAttribute()
|
||||||
{
|
{
|
||||||
return new Attribute(
|
return new Attribute(
|
||||||
function (?string $value): ?string {
|
function (?string $value): ?string {
|
||||||
|
|||||||
@@ -103,4 +103,8 @@ class Simple extends Model
|
|||||||
public function getAttributeReturnsVoidAttribute(): void
|
public function getAttributeReturnsVoidAttribute(): void
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getInvalidAccessModifierAttribute()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,4 +133,8 @@ class Simple extends Model
|
|||||||
public function getAttributeReturnsVoidAttribute(): void
|
public function getAttributeReturnsVoidAttribute(): void
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getInvalidAccessModifierAttribute()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user