| name | custom-handler-creator |
|---|---|
| description | Guide users through creating custom translation handlers for unsupported field types. Use when user asks to "create custom handler", "handle encrypted fields", "handle computed properties", "handle value objects", "extend handler chain", "custom translation handler", or needs to translate field types not supported by built-in handlers. |
When triggered, announce: "I'll use the custom-handler-creator skill to guide you through creating a custom translation handler."
Ask: "What field type needs custom handling?"
Show common examples from examples.md:
- Encrypted fields (decrypt before clone, re-encrypt)
- Computed properties (recalculate in target locale)
- Value objects without Doctrine metadata
- File paths/URLs (transform for locale)
- Third-party library objects
Ask: "What should happen during translation for this field type?"
Gather requirements:
- supports(): What condition identifies this field type?
- translate(): How should the value be cloned/transformed?
- handleSharedAmongstTranslations(): Return same instance or throw exception?
- handleEmptyOnTranslate(): Return null, empty instance, or special value? Use TypeDefaultResolver to return type-safe defaults for non-nullable types (v2.0 pattern)
Show priority matrix from handler-priority.md.
Ask: "Where should your handler fit in the chain?"
Guide selection:
- Must run BEFORE handlers that would incorrectly match the field
- Must run AFTER handlers that should take precedence
- Recommend insertion points: 75, 65, 55, 45, 35, 25, 15
Provide reasoning: "Priority X recommended because [specific reason]"
Use template from handler-template.md.
Fill in:
- Namespace and class name
supports()condition logic- Implementation for all 4 interface methods
- Dependencies (AttributeHelper, EntityManager, etc.)
Show Symfony service configuration:
# config/services.yaml
App\Translation\Handler\{HandlerName}:
arguments:
$attributeHelper: '@tmi_translation.utils.attribute_helper'
# Optional v2.0 dependencies:
# $typeDefaultResolver: '@Tmi\TranslationBundle\Translation\TypeDefaultResolver'
# $cache: '@Tmi\TranslationBundle\Translation\Cache\TranslationCacheInterface'
tags:
- { name: 'tmi_translation.handler', priority: {priority} }Ask: "Want me to add PHPUnit tests for this handler?"
If yes, use template from test-template.md:
- it_supports_[field_type]
- it_does_not_support_other_field_types
- it_translates_[field_type]_correctly
- it_shares_when_marked_shared
- it_returns_null_when_empty
For complete handler chain architecture, priority order, and decision tree, see llms.md "Handler Chain Decision Tree" section.
- EmbeddedHandler now receives
TypeDefaultResolverfor type-safe empty defaults - EntityTranslator now receives
TranslationCacheInterfacefor cache delegation - Custom handlers can inject
TypeDefaultResolverto resolve type-safe defaults forhandleEmptyOnTranslate() - Custom handlers can inject
TranslationCacheInterfaceto check/store translations
All handlers implement these 4 methods:
public function supports(TranslationArgs $args): bool;
public function handleSharedAmongstTranslations(TranslationArgs $args): mixed;
public function handleEmptyOnTranslate(TranslationArgs $args): mixed;
public function translate(TranslationArgs $args): mixed;See handler-template.md for complete implementation template.