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

<!-- myadmin-contract-harness-notice -->

⚠️ Read this before the rest of the file

This package is on the shared plugin contract harness. Parts of the guidance below predate it and are now wrong in one specific way:

Any instruction here that a plugin's getHooks() / getSettings() / getActivate() / getDeactivate() / getQueue() must not be called — that only its existence, visibility or parameter count may be checked through ReflectionClass — no longer applies. That rule existed because those methods reference bare constants (PRORATE_BILLING and friends) that only a live MyAdmin request defines, so calling them from a test used to fatal. The harness defines them first. It then executes the handlers for real, in a process of its own.

A reflection-only assertion passes whether or not the thing works: getActivate() can exist, be public, be static, take one argument, and still fatal the moment it runs. Three real production bugs in this fleet were sitting behind assertions of exactly that shape.

Use the plugin-contract-tests skill for anything touching tests/ContractTest.php, the contract inspectors, or composer myadmin:scaffold-tests.

Everything else in this file is still accurate and still applies — this package's own classes, its API wrappers, its fixtures, its bootstrap, and the reasons certain classes must not be constructed. Nothing below has been removed.

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)05moReviewIntermediate
laravel-specialist124moNo flagsIntermediate
developing-with-turbo-streams16moNo flagsIntermediate
payment-integration17moReviewIntermediate

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