Skip to content

Commit 7be808a

Browse files
committed
Read attribute mutator type from parameter
1 parent 057a81e commit 7be808a

File tree

3 files changed

+169
-38
lines changed

3 files changed

+169
-38
lines changed

src/Console/ModelsCommand.php

+29-24
Original file line numberDiff line numberDiff line change
@@ -604,22 +604,15 @@ public function getPropertiesFromMethods($model)
604604
$this->setProperty($name, $type, true, null, $comment);
605605
}
606606
} elseif ($isAttribute) {
607-
$name = Str::snake($methodReflection->getName());
608-
$types = $this->getAttributeReturnType($model, $methodReflection);
609-
$comment = $this->getCommentFromDocBlock($methodReflection);
610-
611-
if ($types->has('get')) {
612-
$type = $this->getTypeInModel($model, $types['get']);
613-
$this->setProperty($name, $type, true, null, $comment);
614-
}
615-
616-
if ($types->has('set')) {
617-
$this->setProperty($name, null, null, true, $comment);
618-
}
619-
620-
if (!$types->hasAny('get', 'set')) {
621-
$this->setProperty($name, null, true, null, $comment);
622-
}
607+
$types = $this->getAttributeTypes($model, $methodReflection);
608+
$type = $this->getTypeInModel($model, $types->get('get') ?: $types->get('set')) ?: null;
609+
$this->setProperty(
610+
Str::snake($methodReflection->getName()),
611+
$type,
612+
$types->has('get'),
613+
$types->has('set'),
614+
$this->getCommentFromDocBlock($methodReflection)
615+
);
623616
} elseif (
624617
Str::startsWith($methodReflection->getName(), 'set') && Str::endsWith(
625618
$methodReflection->getName(),
@@ -1121,21 +1114,33 @@ protected function hasCamelCaseModelProperties()
11211114
return $this->laravel['config']->get('ide-helper.model_camel_case_properties', false);
11221115
}
11231116

1124-
protected function getAttributeReturnType(Model $model, \ReflectionMethod $reflectionMethod): Collection
1117+
protected function getAttributeTypes(Model $model, \ReflectionMethod $reflectionMethod): Collection
11251118
{
11261119
// Private/protected ReflectionMethods require setAccessible prior to PHP 8.1
11271120
$reflectionMethod->setAccessible(true);
11281121

11291122
/** @var Attribute $attribute */
11301123
$attribute = $reflectionMethod->invoke($model);
11311124

1132-
return collect([
1133-
'get' => $attribute->get ? optional(new \ReflectionFunction($attribute->get))->getReturnType() : null,
1134-
'set' => $attribute->set ? optional(new \ReflectionFunction($attribute->set))->getReturnType() : null,
1135-
])
1136-
->filter()
1125+
$methods = new Collection();
1126+
1127+
if ($attribute->get) {
1128+
$methods['get'] = optional(new \ReflectionFunction($attribute->get))->getReturnType();
1129+
}
1130+
if ($attribute->set) {
1131+
$function = optional(new \ReflectionFunction($attribute->set));
1132+
if ($function->getNumberOfParameters() === 0) {
1133+
$methods['set'] = null;
1134+
} else {
1135+
$methods['set'] = $function->getParameters()[0]->getType();
1136+
}
1137+
}
1138+
1139+
return $methods
11371140
->map(function ($type) {
1138-
if ($type instanceof \ReflectionUnionType) {
1141+
if ($type === null) {
1142+
$types = collect([]);
1143+
} elseif ($type instanceof \ReflectionUnionType) {
11391144
$types = collect($type->getTypes())
11401145
/** @var ReflectionType $reflectionType */
11411146
->map(function ($reflectionType) {
@@ -1146,7 +1151,7 @@ protected function getAttributeReturnType(Model $model, \ReflectionMethod $refle
11461151
$types = collect($this->extractReflectionTypes($type));
11471152
}
11481153

1149-
if ($type->allowsNull()) {
1154+
if ($type && $type->allowsNull()) {
11501155
$types->push('null');
11511156
}
11521157

tests/Console/ModelsCommand/Attributes/Models/Simple.php

+66-6
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,89 @@
99

1010
class Simple extends Model
1111
{
12+
// With a backed property
1213
protected function name(): Attribute
1314
{
1415
return new Attribute(
1516
function (?string $name): ?string {
1617
return $name;
1718
},
1819
function (?string $name): ?string {
19-
return $name === null ? null : ucfirst($name);
20+
return $name;
21+
}
22+
);
23+
}
24+
25+
// Without backed properties
26+
27+
protected function typeHintedGetAndSet(): Attribute
28+
{
29+
return new Attribute(
30+
function (): ?string {
31+
return $this->name;
32+
},
33+
function (?string $name) {
34+
$this->name = $name;
2035
}
2136
);
2237
}
2338

24-
public function uppercaseName(): Attribute
39+
protected function divergingTypeHintedGetAndSet(): Attribute
2540
{
26-
return Attribute::get(function (): string {
27-
return strtoupper($this->name);
41+
return new Attribute(
42+
function (): int {
43+
return strlen($this->name);
44+
},
45+
function (?string $name) {
46+
$this->name = $name;
47+
}
48+
);
49+
}
50+
51+
protected function typeHintedGet(): Attribute
52+
{
53+
return Attribute::get(function (): ?string {
54+
return $this->name;
2855
});
2956
}
3057

31-
public function lowercaseName(): Attribute
58+
protected function typeHintedSet(): Attribute
59+
{
60+
return Attribute::set(function (?string $name) {
61+
$this->name = $name;
62+
});
63+
}
64+
65+
protected function nonTypeHintedGetAndSet(): Attribute
66+
{
67+
return new Attribute(
68+
function () {
69+
return $this->name;
70+
},
71+
function ($name) {
72+
$this->name = $name;
73+
}
74+
);
75+
}
76+
77+
protected function nonTypeHintedGet(): Attribute
3278
{
3379
return Attribute::get(function () {
34-
return strtolower($this->name);
80+
return $this->name;
81+
});
82+
}
83+
84+
protected function nonTypeHintedSet(): Attribute
85+
{
86+
return Attribute::set(function ($name) {
87+
$this->name = $name;
88+
});
89+
}
90+
91+
protected function parameterlessSet(): Attribute
92+
{
93+
return Attribute::set(function () {
94+
$this->name = null;
3595
});
3696
}
3797

tests/Console/ModelsCommand/Attributes/__snapshots__/Test__test__1.php

+74-8
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,15 @@
1111
* Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Attributes\Models\Simple
1212
*
1313
* @property integer $id
14-
* @property-read mixed $lowercase_name
14+
* @property int $diverging_type_hinted_get_and_set
1515
* @property string|null $name
16-
* @property-read string $uppercase_name
16+
* @property-read mixed $non_type_hinted_get
17+
* @property mixed $non_type_hinted_get_and_set
18+
* @property-write mixed $non_type_hinted_set
19+
* @property-write mixed $parameterless_set
20+
* @property-read string|null $type_hinted_get
21+
* @property string|null $type_hinted_get_and_set
22+
* @property-write string|null $type_hinted_set
1723
* @method static \Illuminate\Database\Eloquent\Builder|Simple newModelQuery()
1824
* @method static \Illuminate\Database\Eloquent\Builder|Simple newQuery()
1925
* @method static \Illuminate\Database\Eloquent\Builder|Simple query()
@@ -22,29 +28,89 @@
2228
*/
2329
class Simple extends Model
2430
{
31+
// With a backed property
2532
protected function name(): Attribute
2633
{
2734
return new Attribute(
2835
function (?string $name): ?string {
2936
return $name;
3037
},
3138
function (?string $name): ?string {
32-
return $name === null ? null : ucfirst($name);
39+
return $name;
40+
}
41+
);
42+
}
43+
44+
// Without backed properties
45+
46+
protected function typeHintedGetAndSet(): Attribute
47+
{
48+
return new Attribute(
49+
function (): ?string {
50+
return $this->name;
51+
},
52+
function (?string $name) {
53+
$this->name = $name;
3354
}
3455
);
3556
}
3657

37-
public function uppercaseName(): Attribute
58+
protected function divergingTypeHintedGetAndSet(): Attribute
3859
{
39-
return Attribute::get(function (): string {
40-
return strtoupper($this->name);
60+
return new Attribute(
61+
function (): int {
62+
return strlen($this->name);
63+
},
64+
function (?string $name) {
65+
$this->name = $name;
66+
}
67+
);
68+
}
69+
70+
protected function typeHintedGet(): Attribute
71+
{
72+
return Attribute::get(function (): ?string {
73+
return $this->name;
4174
});
4275
}
4376

44-
public function lowercaseName(): Attribute
77+
protected function typeHintedSet(): Attribute
78+
{
79+
return Attribute::set(function (?string $name) {
80+
$this->name = $name;
81+
});
82+
}
83+
84+
protected function nonTypeHintedGetAndSet(): Attribute
85+
{
86+
return new Attribute(
87+
function () {
88+
return $this->name;
89+
},
90+
function ($name) {
91+
$this->name = $name;
92+
}
93+
);
94+
}
95+
96+
protected function nonTypeHintedGet(): Attribute
4597
{
4698
return Attribute::get(function () {
47-
return strtolower($this->name);
99+
return $this->name;
100+
});
101+
}
102+
103+
protected function nonTypeHintedSet(): Attribute
104+
{
105+
return Attribute::set(function ($name) {
106+
$this->name = $name;
107+
});
108+
}
109+
110+
protected function parameterlessSet(): Attribute
111+
{
112+
return Attribute::set(function () {
113+
$this->name = null;
48114
});
49115
}
50116

0 commit comments

Comments
 (0)