PL

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.zip

Installs 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.
361 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Intermediate

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

You give it
Request to add an event handler or new hook
You get back
A new static event handler method in src/Plugin.php, registered and tested

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 $event properties directly
  • ACL checks require $GLOBALS['tf']->ima == 'admin' guard BEFORE calling has_acl(); call function_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

  1. Identify the event name and subject type. Determine the Symfony event string (e.g. 'system.settings', 'ui.menu') and what getSubject() returns (e.g. \MyAdmin\Settings, \MyAdmin\Plugins\Loader, a menu array). Verify the event string matches a hook registered elsewhere in MyAdmin before proceeding.

  2. Add the PHPDoc block and method signature to src/Plugin.php after the last existing handler, inside the Plugin class:

	/**
	 * @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.

  1. Add ACL guard if the handler renders UI or mutates admin data. Mirror the pattern from getMenu() in src/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.

  1. 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.

  1. Add a test in tests/PluginTest.php using ReflectionClass to 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.

  1. Run tests to verify nothing is broken. Verify src/Plugin.php and tests/PluginTest.php pass 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:

  1. 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');
	}
  1. Update getHooks() return array to add 'module.load' => [__CLASS__, 'getLoad'].
  2. Add testGetLoadMethodSignature() to tests/PluginTest.php and add 'getLoad' to $expectedMethods in testClassPublicMethods().
  3. 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() — missing function_requirements('has_acl'); call before has_acl(). Add it immediately before the if (has_acl(...)) line.
  • testClassPublicMethods fails with "Missing public method: getMyFeature" — you added the method but forgot to add 'getMyFeature' to $expectedMethods in 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.
  • testGetHooksReturnsEmptyArray fails after enabling a hook — this test asserts assertEmpty($hooks). Update it to assertNotEmpty($hooks) or replace with a count assertion once hooks are active.
  • Indentation lint errors in .scrutinizer.yml check — 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.

SkillInstallsUpdatedSafetyDifficulty
plugin-event-handler (this skill)04moReviewIntermediate
laravel-specialist122moNo flagsIntermediate
developing-with-turbo-streams14moNo flagsIntermediate
payment-integration15moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

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.

1215

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.

15

payment-integration

mrgoonie

Integrate payments with SePay (VietQR), Polar, Stripe, Paddle (MoR subscriptions), Creem.io (licensing). Checkout, webhooks, subscriptions, QR codes, multi-provider orders.

13

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.

12

restapi-translations

mikopbx

Управление переводами REST API ключей (rest_*) для MikoPBX. Автоматически находит отсутствующие русские ключи в RestApi.php и синхронизирует их с исходным кодом. Использовать при проверке переводов API, после добавления новых endpoints или перед релизом.

11

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.

10

Search skills

Search the agent skills registry