plugin-event-handler
Automates the boilerplate for adding event hooks to MyAdmin plugins.
Install
mkdir -p .claude/skills/plugin-event-handler && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/18105" && unzip -o skill.zip -d .claude/skills/plugin-event-handler && rm skill.zipInstalls to .claude/skills/plugin-event-handler
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Adds a new static event handler method to `src/Plugin.php` following the `GenericEvent` pattern. Use when user says 'add event handler', 'new hook', 'add to getHooks', or needs to extend plugin functionality. Handles `getSubject()` extraction, ACL checks, and `getHooks()` registration. Do NOT use for modifying existing handlers or creating new plugin classes.Key capabilities
- →Add a new static event handler method to src/Plugin.php
- →Handle getSubject() extraction
- →Perform ACL checks
- →Register handlers in getHooks()
- →Add PHPDoc blocks and method signatures
- →Add tests for method signatures
How it works
The skill adds a new static event handler method to `src/Plugin.php` following the `GenericEvent` pattern, including PHPDoc, ACL checks, and registration in `getHooks()`.
Inputs & outputs
When to use plugin-event-handler
- →Adding new event hooks
- →Registering plugin functionality
- →Implementing Symfony event listeners
About this skill
plugin-event-handler
Critical
- All handler methods MUST be
public static— never instance methods - Parameter type hint MUST be
\Symfony\Component\EventDispatcher\GenericEvent $event - Subject is ALWAYS extracted via
$event->getSubject()— never access$eventproperties directly - ACL checks require
$GLOBALS['tf']->ima == 'admin'guard BEFORE callinghas_acl(); callfunction_requirements('has_acl')first - Use tabs for indentation (not spaces) — enforced by
.scrutinizer.yml - After adding a handler, you MUST uncomment or add its entry in
getHooks()to activate it
Instructions
-
Identify the event name and subject type. Determine the Symfony event string (e.g.
'system.settings','ui.menu') and whatgetSubject()returns (e.g.\MyAdmin\Settings,\MyAdmin\Plugins\Loader, a menu array). Verify the event string matches a hook registered elsewhere in MyAdmin before proceeding. -
Add the PHPDoc block and method signature to
src/Plugin.phpafter the last existing handler, inside thePluginclass:
/**
* @param \Symfony\Component\EventDispatcher\GenericEvent $event
*/
public static function getMyFeature(GenericEvent $event)
{
/**
* @var \MyAdmin\SomeType $subject
**/
$subject = $event->getSubject();
}
Replace getMyFeature with a camelCase name matching the event purpose. Verify the method does not already exist before adding.
- Add ACL guard if the handler renders UI or mutates admin data. Mirror the pattern from
getMenu()insrc/Plugin.php:
if ($GLOBALS['tf']->ima == 'admin') {
function_requirements('has_acl');
if (has_acl('client_billing')) {
// admin-only logic here
}
}
Skip this block for handlers like getRequirements or getSettings that run unconditionally.
- Register the handler in
getHooks(). Add the event→callable entry using__CLASS__:
public static function getHooks()
{
return [
'system.settings' => [__CLASS__, 'getSettings'],
'my.event.name' => [__CLASS__, 'getMyFeature'],
];
}
Verify no duplicate event key exists in the returned array.
- Add a test in
tests/PluginTest.phpusingReflectionClassto assert the method signature:
public function testGetMyFeatureMethodSignature(): void
{
$method = $this->reflection->getMethod('getMyFeature');
$this->assertTrue($method->isStatic());
$this->assertTrue($method->isPublic());
$params = $method->getParameters();
$this->assertCount(1, $params);
$this->assertSame('event', $params[0]->getName());
$paramType = $params[0]->getType();
$this->assertNotNull($paramType);
$this->assertSame(GenericEvent::class, $paramType->getName());
}
Also update testClassPublicMethods() to include 'getMyFeature' in $expectedMethods.
- Run tests to verify nothing is broken. Verify
src/Plugin.phpandtests/PluginTest.phppass syntax and the full test suite is green:
php -l src/Plugin.php && php -l tests/PluginTest.php
All tests must pass before considering the task complete.
Examples
User says: "Add an event handler for the module.load event that registers a service with the loader."
Actions taken:
- Add to
src/Plugin.php:
/**
* @param \Symfony\Component\EventDispatcher\GenericEvent $event
*/
public static function getLoad(GenericEvent $event)
{
/**
* @var \MyAdmin\Plugins\Loader $loader
**/
$loader = $event->getSubject();
$loader->add_requirement('class.Kayako', '/../vendor/detain/myadmin-kayako-chat/src/Kayako.php');
}
- Update
getHooks()return array to add'module.load' => [__CLASS__, 'getLoad']. - Add
testGetLoadMethodSignature()totests/PluginTest.phpand add'getLoad'to$expectedMethodsintestClassPublicMethods(). - Run syntax check and full test suite — all tests pass.
Result: Handler is registered, activated, and covered by a signature test.
Common Issues
Call to undefined function has_acl()— missingfunction_requirements('has_acl');call beforehas_acl(). Add it immediately before theif (has_acl(...))line.testClassPublicMethodsfails with "Missing public method: getMyFeature" — you added the method but forgot to add'getMyFeature'to$expectedMethodsin that test.- Hook never fires — method was added but the entry in
getHooks()is still commented out. Uncomment or add the entry to the returned array. testGetHooksReturnsEmptyArrayfails after enabling a hook — this test assertsassertEmpty($hooks). Update it toassertNotEmpty($hooks)or replace with a count assertion once hooks are active.- Indentation lint errors in
.scrutinizer.ymlcheck — file was saved with spaces. Convert to tabs:unexpand --first-only -t 4 src/Plugin.php > /tmp/p.php && mv /tmp/p.php src/Plugin.php.
When not to use it
- →For modifying existing handlers
- →For creating new plugin classes
Limitations
- →Does not support modifying existing handlers
- →Does not support creating new plugin classes
- →Requires `\Symfony\Component\EventDispatcher\GenericEvent $event` as parameter type hint
How it compares
This skill automates the process of adding and testing new event handlers in a specific plugin structure, ensuring adherence to coding standards, unlike manual implementation that might miss critical steps.
Compared to similar skills
plugin-event-handler side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| plugin-event-handler (this skill) | 0 | 4mo | Review | Intermediate |
| laravel-specialist | 12 | 2mo | No flags | Intermediate |
| developing-with-turbo-streams | 1 | 4mo | No flags | Intermediate |
| payment-integration | 1 | 5mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by myadmin-plugins
View all by myadmin-plugins →You might also like
laravel-specialist
Jeffallan
Use when building Laravel 10+ applications requiring Eloquent ORM, API resources, or queue systems. Invoke for Laravel models, Livewire components, Sanctum authentication, Horizon queues.
developing-with-turbo-streams
hotwired-laravel
Basics of developing with Turbo Streams in web applications. Activate when working on projects that utilize Turbo Streams for enhancing user experience through real-time updates, dynamic content changes, and partial page updates without full reloads.
payment-integration
mrgoonie
Integrate payments with SePay (VietQR), Polar, Stripe, Paddle (MoR subscriptions), Creem.io (licensing). Checkout, webhooks, subscriptions, QR codes, multi-provider orders.
developing-with-prism
prism-php
Guide for developing with Prism PHP package - a Laravel package for integrating LLMs. Activate or use when working with Prism features including text generation, structured output, embeddings, image generation, audio processing, streaming, tools/function calling, or any LLM provider integration (OpenAI, Anthropic, Gemini, Mistral, Groq, XAI, DeepSeek, OpenRouter, Ollama, VoyageAI, ElevenLabs). Activate for any Prism-related development tasks.
restapi-translations
mikopbx
Управление переводами REST API ключей (rest_*) для MikoPBX. Автоматически находит отсутствующие русские ключи в RestApi.php и синхронизирует их с исходным кодом. Использовать при проверке переводов API, после добавления новых endpoints или перед релизом.
moodle-external-api-development
davila7
Create custom external web service APIs for Moodle LMS. Use when implementing web services for course management, user tracking, quiz operations, or custom plugin functionality. Covers parameter validation, database operations, error handling, service registration, and Moodle coding standards.