Skip to content

Commit 43a519c

Browse files
committed
Fix protected or private method access for WP Cli classes
1 parent 6299ca7 commit 43a519c

3 files changed

Lines changed: 46 additions & 9 deletions

File tree

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
"nwidart/laravel-modules": "^12.0@dev",
4141
"symfony/process": "^7.3.4",
4242
"illuminate/config": "^12.34",
43-
"laravel/prompts": "^0.3.7@dev"
43+
"laravel/prompts": "^0.3.7@dev",
44+
"spatie/invade": "dev-main"
4445
},
4546
"autoload": {
4647
"psr-4": {

src/WpCli/Application/Services/WpCliService.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,15 @@ private function registerWithWpCli(string $name, string|array $className, string
6161
try {
6262
// If it's an array (callable), validate the class exists
6363
if (is_array($className)) {
64-
if (!class_exists($className[0])) {
64+
// Handle anonymous classes (like our invade wrapper)
65+
if (is_object($className[0])) {
66+
// For anonymous classes, we can't validate with class_exists
67+
// but we can check if the method exists
68+
if (!method_exists($className[0], $className[1])) {
69+
error_log("WP CLI command method {$className[1]} does not exist on anonymous class");
70+
return;
71+
}
72+
} elseif (!class_exists($className[0])) {
6573
error_log("WP CLI command class {$className[0]} does not exist");
6674
return;
6775
}

src/WpCli/Infrastructure/Services/WpCliDiscovery.php

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -257,26 +257,26 @@ private function processSubcommands(ReflectionClass $reflectionClass, string $cl
257257
$args
258258
);
259259

260-
// Then register private/protected methods with Command attributes as individual subcommands
260+
// Then register methods with Command attributes as individual subcommands
261261
foreach ($reflectionClass->getMethods() as $method) {
262262
$commandAttributes = $method->getAttributes(Command::class);
263263

264264
if ($commandAttributes === []) {
265265
continue;
266266
}
267267

268-
// Skip if method is public (already handled by base class registration)
269-
if ($method->isPublic()) {
270-
continue;
271-
}
272-
273268
/** @var Command $commandAttribute */
274269
$commandAttribute = $commandAttributes[0]->newInstance();
275270
$subcommandName = $commandAttribute->getSubcommandName($method->getName());
276271
$fullCommandName = "{$baseCommandName} {$subcommandName}";
277272

278273
// Create a callable array for the subcommand
279-
$callable = [$className, $method->getName()];
274+
// For private/protected methods, we need to use a wrapper with invade
275+
if ($method->isPrivate() || $method->isProtected()) {
276+
$callable = $this->createInvadeWrapper($className, $method->getName());
277+
} else {
278+
$callable = [$className, $method->getName()];
279+
}
280280

281281
// Register subcommand with WP CLI using method-level arguments
282282
if (\defined('WP_CLI') && WP_CLI) {
@@ -329,6 +329,34 @@ private function collectMethodArguments(ReflectionMethod $reflectionMethod): arr
329329
return $this->collectWpCliArguments($reflectionMethod);
330330
}
331331

332+
/**
333+
* Create an invade wrapper for calling private/protected methods.
334+
*
335+
* @param string $className The class name
336+
* @param string $methodName The method name
337+
* @return array A callable array that uses invade
338+
*/
339+
private function createInvadeWrapper(string $className, string $methodName): array
340+
{
341+
return [new class($className, $methodName) {
342+
private string $className;
343+
private string $methodName;
344+
345+
public function __construct(string $className, string $methodName)
346+
{
347+
$this->className = $className;
348+
$this->methodName = $methodName;
349+
}
350+
351+
public function __invoke(array $args, array $assocArgs): mixed
352+
{
353+
$instance = app($this->className);
354+
$invadedInstance = invade($instance);
355+
return $invadedInstance->{$this->methodName}($args, $assocArgs);
356+
}
357+
}, '__invoke'];
358+
}
359+
332360
/**
333361
* Collect WP CLI arguments from reflection attributes.
334362
*

0 commit comments

Comments
 (0)