typeValidator = new ParameterTypeValidator(); } public function getAttributeClass(): string { return ConsoleCommand::class; } public function map(WrappedReflectionClass|WrappedReflectionMethod $reflectionTarget, object $attributeInstance): ?array { if (! $reflectionTarget instanceof WrappedReflectionMethod) { return null; // ConsoleCommand can only be applied to methods } // Check if method has multiple attributes (multi-purpose) $hasMultipleAttributes = $this->hasMultiplePurposeAttributes($reflectionTarget); // If multi-purpose, validate that all parameters are builtin types if ($hasMultipleAttributes) { $parameters = $reflectionTarget->getParameters()->toArray(); $reflectionParameters = []; foreach ($parameters as $param) { $reflectionParameters[] = $param->getType(); } if (! $this->typeValidator->hasOnlyBuiltinParameters($reflectionParameters)) { // Skip this attribute if parameters are not all builtin return null; } } // Get other attributes for metadata $otherAttributes = $this->getOtherPurposeAttributes($reflectionTarget); return [ 'attribute_data' => [ 'name' => $attributeInstance->name, 'description' => $attributeInstance->description, ], 'class' => $reflectionTarget->getDeclaringClass(), 'method' => $reflectionTarget->getName(), 'multi_purpose' => $hasMultipleAttributes, 'other_attributes' => $otherAttributes, ]; } /** * Check if method has multiple purpose attributes (McpTool, ConsoleCommand, Route) */ private function hasMultiplePurposeAttributes(WrappedReflectionMethod $method): bool { $attributes = $method->getAttributes(); $purposeAttributeCount = 0; foreach ($attributes as $attribute) { $attributeName = $attribute->getName(); if (in_array($attributeName, [ McpTool::class, ConsoleCommand::class, Route::class, ], true)) { $purposeAttributeCount++; } } return $purposeAttributeCount > 1; } /** * Get other purpose attributes on the same method * * @return array */ private function getOtherPurposeAttributes(WrappedReflectionMethod $method): array { $attributes = $method->getAttributes(); $otherAttributes = []; foreach ($attributes as $attribute) { $attributeName = $attribute->getName(); if (in_array($attributeName, [ McpTool::class, Route::class, ], true)) { $otherAttributes[] = $attributeName; } } return $otherAttributes; } }