Skip to content

Commit 908b982

Browse files
committed
Cleaned up more of the code and ran the fixer
1 parent 9895894 commit 908b982

28 files changed

+1182
-237
lines changed

.php-cs-fixer.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
use Cego\CegoFixer;
4+
5+
$finder = PhpCsFixer\Finder::create()
6+
->in(__DIR__ . '/src')
7+
->in(__DIR__ . '/test');
8+
9+
return CegoFixer::applyRules($finder, [
10+
'ternary_to_null_coalescing' => true,
11+
]);

composer.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
}
2323
},
2424
"require": {
25-
"php": "^7.4|^8.0",
26-
"nunomaduro/larastan": "^2.1",
27-
"phpstan/phpstan": "^1.4"
25+
"php": "^8.1"
2826
},
2927
"require-dev": {
30-
"spatie/laravel-data": "^3.0"
28+
"spatie/laravel-data": "^3.0",
29+
"phpunit/phpunit": "^10.0",
30+
"phpstan/phpstan": "^1.4",
31+
"nunomaduro/larastan": "^2.4",
32+
"cego/php-cs-fixer": "^1.0"
3133
}
3234
}

extension.neon

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
includes:
2-
- ./../../nunomaduro/larastan/extension.neon
1+
#includes:
2+
# - ./../../nunomaduro/larastan/extension.neon
33

44
services:
55
-

src/SpatieLaravelData/Collectors/CastCollector.php

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
namespace Cego\phpstan\SpatieLaravelData\Collectors;
44

55
use PhpParser\Node;
6-
use PHPStan\Analyser\Scope;
76
use Illuminate\Support\Str;
7+
use PHPStan\Analyser\Scope;
88
use PHPStan\Type\VerbosityLevel;
99
use PHPStan\Collectors\Collector;
10-
use Spatie\LaravelData\Casts\Cast;
1110
use Illuminate\Support\Collection;
11+
use Spatie\LaravelData\Casts\Cast;
1212
use PhpParser\Node\Expr\StaticCall;
1313
use PHPStan\Node\InClassMethodNode;
1414
use PHPStan\ShouldNotHappenException;
15+
use Cego\phpstan\TypeSystem\UnionType;
1516
use Spatie\LaravelData\Casts\Uncastable;
1617
use PHPStan\Reflection\ParametersAcceptorSelector;
1718

@@ -34,10 +35,12 @@ public function getNodeType(): string
3435
* Process the nodes and stores value in the collector instance
3536
*
3637
* @phpstan-param StaticCall $node
37-
* @return array<int, array<int, string>|null Collected data
38+
*
3839
* @throws ShouldNotHappenException
40+
*
41+
* @return string|null Collected data
3942
*/
40-
public function processNode(Node $node, Scope $scope): ?array
43+
public function processNode(Node $node, Scope $scope): ?string
4144
{
4245
// Skip wrong nodes
4346
if ( ! $node instanceof InClassMethodNode) {
@@ -68,15 +71,15 @@ public function processNode(Node $node, Scope $scope): ?array
6871

6972
// We only support intersection types of explicit classes / interfaces.
7073
if ($intersectionTypes->count() !== $classTypes->count()) {
71-
return collect();
74+
return [];
7275
}
7376

74-
return $classTypes;
77+
return $classTypes->all();
7578
})
7679
// Remove any intersection types we have deemed unfit
77-
->reject(fn (Collection $collection) => $collection->isEmpty())
78-
// And array the result so it can be serialized by PhpStan
79-
->toArray();
80+
->reject(fn (array $collection) => empty($collection))
81+
->pipe(UnionType::fromRaw(...))
82+
->toString();
8083
}
8184

8285
/**

src/SpatieLaravelData/Collectors/ConstructorCollector.php

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Cego\phpstan\SpatieLaravelData\Collectors;
44

55
use PhpParser\Node;
6+
use RuntimeException;
67
use PhpParser\Node\Name;
78
use PhpParser\Node\Param;
89
use PHPStan\Analyser\Scope;
@@ -11,8 +12,10 @@
1112
use PhpParser\Node\ComplexType;
1213
use PHPStan\Collectors\Collector;
1314
use PHPStan\Node\InClassMethodNode;
15+
use Cego\phpstan\TypeSystem\UnionType;
1416
use PHPStan\Reflection\ClassReflection;
15-
use Cego\phpstan\Collectors\RuntimeException;
17+
use Cego\phpstan\SpatieLaravelData\Data\Constructor;
18+
use Cego\phpstan\SpatieLaravelData\Data\KeyTypePair;
1619

1720
/**
1821
* @implements Collector<InClassMethodNode, array<string, array<string, array<int, string>>>
@@ -33,9 +36,10 @@ public function getNodeType(): string
3336
* Process the nodes and stores value in the collector instance
3437
*
3538
* @phpstan-param InClassMethodNode $node
36-
* @return array<string, array<string, array<int, string>>|null Collected data
39+
*
40+
* @return string|null Collected data
3741
*/
38-
public function processNode(Node $node, Scope $scope): ?array
42+
public function processNode(Node $node, Scope $scope): ?string
3943
{
4044
if ( ! $node instanceof InClassMethodNode) {
4145
return null;
@@ -45,27 +49,25 @@ public function processNode(Node $node, Scope $scope): ?array
4549
return null;
4650
}
4751

48-
return [
49-
'class' => $node->getMethodReflection()->getDeclaringClass()->getName(),
50-
'properties' => collect($node->getOriginalNode()->getParams())
51-
->map(fn (Param $param) => $this->getParameterTypes($param))
52-
->all(),
53-
];
52+
return serialize(new Constructor(
53+
$node->getMethodReflection()->getDeclaringClass()->getName(),
54+
collect($node->getOriginalNode()->getParams())->map($this->getParameterTypes(...))->all()
55+
));
5456
}
5557

5658
/**
5759
* Returns a key-value mapping of the parameter name and its allowed types
5860
*
5961
* @param Param $parameter
6062
*
61-
* @return array<string, array<int, string>>
63+
* @return KeyTypePair
6264
*/
63-
private function getParameterTypes(Param $parameter): array
65+
private function getParameterTypes(Param $parameter): KeyTypePair
6466
{
65-
$name = $this->getParameterName($parameter);
66-
$types = $this->parseType($parameter->type);
67-
68-
return [$name => $types];
67+
return new KeyTypePair(
68+
$this->getParameterName($parameter),
69+
UnionType::fromRaw($this->parseType($parameter->type)),
70+
);
6971
}
7072

7173
/**
@@ -118,14 +120,21 @@ private function parseType($type): array
118120
collect($type->types)
119121
->map(fn ($intersectionType) => $this->parseType($intersectionType))
120122
->flatten(2)
121-
->all()
123+
->all(),
122124
];
123125
}
124126
}
125127

126128
return [['mixed']];
127129
}
128130

131+
/**
132+
* Returns the name of the given parameter
133+
*
134+
* @param Param $parameter
135+
*
136+
* @return string
137+
*/
129138
private function getParameterName(Param $parameter): string
130139
{
131140
if ( ! is_string($parameter->var->name)) {
@@ -135,17 +144,38 @@ private function getParameterName(Param $parameter): string
135144
return $parameter->var->name;
136145
}
137146

147+
/**
148+
* Returns true if the given node is not a laravel data constructor
149+
*
150+
* @param InClassMethodNode $node
151+
*
152+
* @return bool
153+
*/
138154
private function isNotSpatieLaravelDataConstructor(InClassMethodNode $node): bool
139155
{
140156
return $this->isNotConstructor($node)
141157
|| $this->isNotSpatieLaravelDataClass($node->getMethodReflection()->getDeclaringClass());
142158
}
143159

160+
/**
161+
* Returns true if the given node is not a constructor class
162+
*
163+
* @param InClassMethodNode $node
164+
*
165+
* @return bool
166+
*/
144167
private function isNotConstructor(InClassMethodNode $node): bool
145168
{
146169
return $node->getMethodReflection()->getName() !== '__construct';
147170
}
148171

172+
/**
173+
* Returns true if the given class is not a laravel data class
174+
*
175+
* @param ClassReflection $class
176+
*
177+
* @return bool
178+
*/
149179
private function isNotSpatieLaravelDataClass(ClassReflection $class): bool
150180
{
151181
return ! in_array(Data::class, $class->getParentClassesNames(), true);

src/SpatieLaravelData/Collectors/FromCollector.php

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
use PHPStan\Collectors\Collector;
1111
use PhpParser\Node\Expr\StaticCall;
1212
use PHPStan\Type\ConstantScalarType;
13+
use Cego\phpstan\TypeSystem\UnionType;
14+
use Cego\phpstan\SpatieLaravelData\Data\Call;
15+
use Cego\phpstan\SpatieLaravelData\Data\Method;
16+
use Cego\phpstan\SpatieLaravelData\Data\KeyTypePair;
1317

1418
/**
1519
* @implements Collector<StaticCall, array<string, array<int, string>>
@@ -30,9 +34,10 @@ public function getNodeType(): string
3034
* Process the nodes and stores value in the collector instance
3135
*
3236
* @phpstan-param StaticCall $node
33-
* @return array<string, array<int, string>|null Collected data
37+
*
38+
* @return string|null Collected data
3439
*/
35-
public function processNode(Node $node, Scope $scope): ?array
40+
public function processNode(Node $node, Scope $scope): ?string
3641
{
3742
if ( ! $node instanceof StaticCall) {
3843
return null;
@@ -63,25 +68,33 @@ public function processNode(Node $node, Scope $scope): ?array
6368
$type = $scope->getType($item->value);
6469

6570
if ($type instanceof ConstantScalarType) {
66-
$argData[$item->key->value] = get_debug_type($type->getValue());
71+
$argData[] = new KeyTypePair($item->key->value, UnionType::fromString(get_debug_type($type->getValue())));
6772
} else {
68-
$argData[$item->key->value] = $scope->getType($item->value)->describe(VerbosityLevel::typeOnly());
73+
$argData[] = new KeyTypePair($item->key->value, UnionType::fromString($scope->getType($item->value)->describe(VerbosityLevel::typeOnly())));
6974
}
7075
}
7176

7277
$types[] = $argData;
7378
}
7479

75-
return [
76-
'types' => $types,
77-
'target' => $this->getTargetClass($node, $scope),
78-
'method' => [
79-
'file' => $scope->getFile(),
80-
'line' => $node->getLine(),
81-
],
82-
];
80+
return serialize(new Call(
81+
$this->getTargetClass($node, $scope),
82+
$types,
83+
new Method(
84+
$scope->getFile(),
85+
$node->getLine(),
86+
)
87+
));
8388
}
8489

90+
/**
91+
* Returns true if the given node is not a laravel data class static ::From call
92+
*
93+
* @param StaticCall $node
94+
* @param Scope $scope
95+
*
96+
* @return bool
97+
*/
8598
private function isNotSpatieLaravelDataFromCall(StaticCall $node, Scope $scope): bool
8699
{
87100
if (strtolower($node->name->name) !== 'from') {
@@ -91,6 +104,14 @@ private function isNotSpatieLaravelDataFromCall(StaticCall $node, Scope $scope):
91104
return ! is_a($this->getTargetClass($node, $scope), Data::class, true);
92105
}
93106

107+
/**
108+
* Returns the target / result class of the given static call
109+
*
110+
* @param StaticCall $node
111+
* @param Scope $scope
112+
*
113+
* @return string
114+
*/
94115
private function getTargetClass(StaticCall $node, Scope $scope)
95116
{
96117
if ($node->class instanceof Node\Expr) {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace Cego\phpstan\SpatieLaravelData\Data;
4+
5+
use Cego\phpstan\SpatieLaravelData\Traits\UnserializesSelf;
6+
7+
class Call
8+
{
9+
use UnserializesSelf;
10+
11+
/**
12+
* Constructor
13+
*
14+
* @param string $target
15+
* @param array<int, array<int, KeyTypePair>> $arrayArguments
16+
* @param Method $method
17+
*/
18+
public function __construct(
19+
public readonly string $target,
20+
public readonly array $arrayArguments,
21+
public readonly Method $method,
22+
) {
23+
}
24+
25+
/**
26+
* Returns array containing all the necessary state of the object.
27+
*/
28+
public function __serialize(): array
29+
{
30+
return [
31+
'target' => $this->target,
32+
'method' => serialize($this->method),
33+
'arrayArguments' => serialize($this->arrayArguments),
34+
];
35+
}
36+
37+
/**
38+
* Restores the object state from the given data array.
39+
*
40+
* @param array $data
41+
*/
42+
public function __unserialize(array $data): void
43+
{
44+
$this->target = $data['target'];
45+
$this->method = Method::unserialize($data['method']);
46+
$this->arrayArguments = unserialize($data['arrayArguments'], ['allowed_classes' => [KeyTypePair::class]]);
47+
}
48+
}

0 commit comments

Comments
 (0)