Skip to content

Commit 46fcd41

Browse files
Merge pull request #333 from laravel/auth-user-docblocks
Better resolution for `$request->user()`, `auth()->user()`, and `Auth::user()`
2 parents 69a2ab3 + 67ab6e1 commit 46fcd41

File tree

5 files changed

+253
-84
lines changed

5 files changed

+253
-84
lines changed

php-templates/auth.php

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,36 @@
1313
])
1414
->filter(fn($policy) => $policy !== null);
1515

16+
function vsCodeGetAuthenticatable() {
17+
try {
18+
$guard = auth()->guard();
19+
20+
$reflection = new \ReflectionClass($guard);
21+
22+
if (!$reflection->hasProperty("provider")) {
23+
return null;
24+
}
25+
26+
$property = $reflection->getProperty("provider");
27+
$provider = $property->getValue($guard);
28+
29+
if ($provider instanceof \Illuminate\Auth\EloquentUserProvider) {
30+
$providerReflection = new \ReflectionClass($provider);
31+
$modelProperty = $providerReflection->getProperty("model");
32+
33+
return str($modelProperty->getValue($provider))->prepend("\\")->toString();
34+
}
35+
36+
if ($provider instanceof \Illuminate\Auth\DatabaseUserProvider) {
37+
return str(\Illuminate\Auth\GenericUser::class)->prepend("\\")->toString();
38+
}
39+
} catch (\Exception | \Throwable $e) {
40+
return null;
41+
}
42+
43+
return null;
44+
}
45+
1646
function vsCodeGetPolicyInfo($policy, $model)
1747
{
1848
$methods = (new ReflectionClass($policy))->getMethods();
@@ -26,38 +56,40 @@ function vsCodeGetPolicyInfo($policy, $model)
2656
])->filter(fn($ability) => !in_array($ability['key'], ['allow', 'deny']));
2757
}
2858

29-
echo collect(\Illuminate\Support\Facades\Gate::abilities())
30-
->map(function ($policy, $key) {
31-
$reflection = new \ReflectionFunction($policy);
32-
$policyClass = null;
33-
$closureThis = $reflection->getClosureThis();
59+
echo json_encode([
60+
'authenticatable' => vsCodeGetAuthenticatable(),
61+
'policies' => collect(\Illuminate\Support\Facades\Gate::abilities())
62+
->map(function ($policy, $key) {
63+
$reflection = new \ReflectionFunction($policy);
64+
$policyClass = null;
65+
$closureThis = $reflection->getClosureThis();
3466

35-
if ($closureThis !== null) {
36-
if (get_class($closureThis) === \Illuminate\Auth\Access\Gate::class) {
37-
$vars = $reflection->getClosureUsedVariables();
67+
if ($closureThis !== null) {
68+
if (get_class($closureThis) === \Illuminate\Auth\Access\Gate::class) {
69+
$vars = $reflection->getClosureUsedVariables();
3870

39-
if (isset($vars['callback'])) {
40-
[$policyClass, $method] = explode('@', $vars['callback']);
71+
if (isset($vars['callback'])) {
72+
[$policyClass, $method] = explode('@', $vars['callback']);
4173

42-
$reflection = new \ReflectionMethod($policyClass, $method);
43-
}
44-
}
45-
}
74+
$reflection = new \ReflectionMethod($policyClass, $method);
75+
}
76+
}
77+
}
4678

47-
return [
48-
'key' => $key,
49-
'uri' => $reflection->getFileName(),
50-
'policy' => $policyClass,
51-
'line' => $reflection->getStartLine(),
52-
];
53-
})
54-
->merge(
55-
collect(\Illuminate\Support\Facades\Gate::policies())->flatMap(fn($policy, $model) => vsCodeGetPolicyInfo($policy, $model)),
56-
)
57-
->merge(
58-
$modelPolicies->flatMap(fn($policy, $model) => vsCodeGetPolicyInfo($policy, $model)),
59-
)
60-
->values()
61-
->groupBy('key')
62-
->map(fn($item) => $item->map(fn($i) => \Illuminate\Support\Arr::except($i, 'key')))
63-
->toJson();
79+
return [
80+
'key' => $key,
81+
'uri' => $reflection->getFileName(),
82+
'policy' => $policyClass,
83+
'line' => $reflection->getStartLine(),
84+
];
85+
})
86+
->merge(
87+
collect(\Illuminate\Support\Facades\Gate::policies())->flatMap(fn($policy, $model) => vsCodeGetPolicyInfo($policy, $model)),
88+
)
89+
->merge(
90+
$modelPolicies->flatMap(fn($policy, $model) => vsCodeGetPolicyInfo($policy, $model)),
91+
)
92+
->values()
93+
->groupBy('key')
94+
->map(fn($item) => $item->map(fn($i) => \Illuminate\Support\Arr::except($i, 'key'))),
95+
]);

src/features/auth.ts

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const toFind: FeatureTag = [
2626
"check",
2727
"any",
2828
"authorize",
29-
"inspect",
29+
"inspect",
3030
],
3131
argumentIndex: 0,
3232
},
@@ -106,7 +106,7 @@ const analyzeParam = (
106106
}
107107

108108
const policies = values
109-
.map((value) => getPolicies().items[value.value])
109+
.map((value) => getPolicies().items.policies[value.value])
110110
.flat();
111111

112112
if (["has"].includes(item.methodName)) {
@@ -301,26 +301,28 @@ export const completionProvider: CompletionProvider = {
301301
return [];
302302
}
303303

304-
return Object.entries(getPolicies().items).map(([key, value]) => {
305-
let completeItem = new vscode.CompletionItem(
306-
key,
307-
vscode.CompletionItemKind.Value,
308-
);
304+
return Object.entries(getPolicies().items.policies).map(
305+
([key, value]) => {
306+
let completeItem = new vscode.CompletionItem(
307+
key,
308+
vscode.CompletionItemKind.Value,
309+
);
309310

310-
completeItem.range = document.getWordRangeAtPosition(
311-
position,
312-
wordMatchRegex,
313-
);
311+
completeItem.range = document.getWordRangeAtPosition(
312+
position,
313+
wordMatchRegex,
314+
);
314315

315-
const policyClasses = value
316-
.map((item) => item.policy)
317-
.filter(String);
316+
const policyClasses = value
317+
.map((item) => item.policy)
318+
.filter(String);
318319

319-
if (policyClasses.length > 0) {
320-
completeItem.detail = policyClasses.join("\n\n");
321-
}
320+
if (policyClasses.length > 0) {
321+
completeItem.detail = policyClasses.join("\n\n");
322+
}
322323

323-
return completeItem;
324-
});
324+
return completeItem;
325+
},
326+
);
325327
},
326328
};

src/repositories/auth.ts

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
import { internalVendorPath } from "@src/support/project";
2+
import fs from "fs";
13
import { repository } from ".";
24
import { runInLaravel, template } from "./../support/php";
35

46
type AuthItems = {
5-
[key: string]: AuthItem[];
7+
authenticatable: string | null;
8+
policies: {
9+
[key: string]: AuthItem[];
10+
};
611
};
712

813
export type AuthItem = {
@@ -12,12 +17,109 @@ export type AuthItem = {
1217
model: string | null;
1318
};
1419

20+
const writeAuthBlocks = (authenticatable: string | null) => {
21+
if (!authenticatable) {
22+
return;
23+
}
24+
25+
const blocks = [
26+
{
27+
file: "_auth.php",
28+
content: `
29+
<?php
30+
31+
namespace Illuminate\\Contracts\\Auth;
32+
33+
interface Guard
34+
{
35+
/**
36+
* @return ${authenticatable}|null
37+
*/
38+
public function user();
39+
}`,
40+
},
41+
{
42+
file: "_request.php",
43+
content: `
44+
<?php
45+
46+
namespace Illuminate\\Http;
47+
48+
interface Request
49+
{
50+
/**
51+
* @return ${authenticatable}|null
52+
*/
53+
public function user($guard = null);
54+
}`,
55+
},
56+
{
57+
file: "_facade.php",
58+
content: `
59+
<?php
60+
61+
namespace Illuminate\\Support\\Facades;
62+
63+
interface Auth
64+
{
65+
/**
66+
* @return ${authenticatable}|false
67+
*/
68+
public static function loginUsingId(mixed $id, bool $remember = false);
69+
70+
/**
71+
* @return ${authenticatable}|false
72+
*/
73+
public static function onceUsingId(mixed $id);
74+
75+
/**
76+
* @return ${authenticatable}|null
77+
*/
78+
public static function getUser();
79+
80+
/**
81+
* @return ${authenticatable}
82+
*/
83+
public static function authenticate();
84+
85+
/**
86+
* @return ${authenticatable}|null
87+
*/
88+
public static function user();
89+
90+
/**
91+
* @return ${authenticatable}|null
92+
*/
93+
public static function logoutOtherDevices(string $password);
94+
95+
/**
96+
* @return ${authenticatable}
97+
*/
98+
public static function getLastAttempted();
99+
}`,
100+
},
101+
];
102+
103+
blocks.forEach((block) => {
104+
fs.writeFileSync(internalVendorPath(block.file), block.content.trim());
105+
});
106+
};
107+
15108
const load = () => {
16-
return runInLaravel<AuthItems>(template("auth"), "Auth Data");
109+
return runInLaravel<AuthItems>(template("auth"), "Auth Data").then(
110+
(result) => {
111+
writeAuthBlocks(result.authenticatable);
112+
113+
return result;
114+
},
115+
);
17116
};
18117

19118
export const getPolicies = repository<AuthItems>({
20119
load,
21120
pattern: "app/Providers/{,*,**/*}.php",
22-
itemsDefault: {},
121+
itemsDefault: {
122+
authenticatable: null,
123+
policies: {},
124+
},
23125
});

src/repositories/translations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,6 @@ export const getTranslations = repository<TranslationGroupResult>({
8383
itemsDefault: {
8484
default: "",
8585
translations: {},
86+
languages: [],
8687
},
8788
});

0 commit comments

Comments
 (0)