A PhpStorm/IntelliJ plugin that enhances PHP development workflow with advanced navigation and code analysis features, particularly focused on Symfony Messenger pattern and peer navigation capabilities.
- Smart Navigation: Navigate from message dispatch calls directly to their corresponding handlers
- Find Usages: Discover all dispatch calls for a specific message class or handler method
- Message Detection: Automatically identify message classes based on naming patterns and interfaces
- Handler Detection: Recognize message handlers through interfaces, attributes, or naming conventions
- Multi-dispatch Support: Support for various dispatch method names (
dispatch,query,command,handle)
- Pattern-based Navigation: Navigate between related classes using regex patterns
- Flexible Mapping: Define custom source-to-target class relationships
- Go to Declaration: Jump between peer classes with a single keystroke
- Associate Navigation: Navigate between associated classes based on custom relationships
- Multi-direction Support: Navigate bidirectionally between associated classes
- Attribute-based Navigation: Open a intellij search with a formatted value of an attribute property
- Flexible Mapping: Define custom attribute property and a formatter to generate a custom intellij search pattern
- Click and search: Jump between peer classes with a single keystroke
- Markdown Export: Export source code to markdown format optimized for LLMs
- Code Context Preservation: Maintain code structure and relationships in exported format, could also add all related classes found in specific namespaces.
- Custom Formatting: Configure export format settings
- Selective Export: Choose specific files or directories to export
- .aiignore: .aiignore file is used to filter files to export
- Freely inspired from https://github.com/keyboardsamurai/source-clipboard-export-intellij-plugin which was dedicated to Java project
- Command Output Analysis: Parse and analyze CLI dumper output
- Structured Data Extraction: Convert raw CLI output into structured format (JSON ou short syntac PHP arrays)
- Integration Support: Seamless integration with development workflow
- Supports filtering and searching
- Double-click to navigate to command implementation
- Provides direct navigation to route definitions
- Commands Panel: Shows command descriptions and usage information
- Routes Panel: Displays route path, name, and methods
- Doctrine Entities Panel: Displays name, tableName and schema
- Hot Reload: Configuration changes are automatically detected and applied
- Multiple Formats: Support for JSON and YAML configuration files
- Hierarchical Config: Local configuration files can override global settings
- Real-time Notifications: Get notified when configuration is loaded or encounters errors
The plugin uses configuration files placed in your project root. The plugin will automatically detect and load configuration from any of these files (in order of precedence):
.php-companion.yaml.php-companion.json.php-companion.local.yaml.php-companion.local.json
attributeNavigation:
rules:
- actionType: find_in_file
attributeFQCN: \Symfony\Component\Routing\Attribute\Route
fileMask: '*.yaml,*.yml,*.php'
formatterScript: |
return (value.replaceAll("(\\{.*?\\})", "[^/]*")+ ":");
isDefault: true
propertyName: path
commands:
attributeFQCN: \Symfony\Component\Console\Attribute\AsCommand
enabled: true
namespaces:
- \App
- \Application
consoleCleaner:
patterns:
- ''
doctrineEntities:
attributeFQCN: \Doctrine\ORM\Mapping\Table
enabled: true
namespaces:
- \Domain
- \Entity
exportSourceToMarkdown:
contextualNamespaces:
- App\Core\Models
template: |
[# th:each="file : ${files}"]
## [(${file.path})]
````[(${file.extension})]
[(${file.content})]
````
[/]
useContextualNamespaces: true
useIgnoreFile: true
openAPI:
enabled: true
specificationRoots:
- ''
peerNavigation:
associates:
- classA: \\App\\Tests\\Func\\(?<type>.*)\\Web\\(?<path>.*)\\ControllerTest
classB: \\App\\(?<type>.*)\\Web\\(?<path>.*)\\Controller
peers:
- source: ''
target: ''
routes:
attributeFQCN: \Symfony\Component\Routing\Attribute\Route
enabled: true
namespaces:
- \App
- \Application
symfonyMessenger:
asMessageHandlerAttribute: Symfony\Component\Messenger\Attribute\AsMessageHandler
dispatchMethods:
- dispatch
- query
- command
- handle
handlerMethods:
- __invoke
- handle
messageClassNamePatterns: .*(Message|Command|Query|Event|Input)$
messageHandlerInterfaces:
- Symfony\Component\Messenger\Handler\MessageHandlerInterface
messageInterfaces:
- ''
projectRootNamespace: \App
useNativeGoToDeclaration: false
| Property | Description |
|---|---|
| asMessageHandlerAttribute | FQCN of the attribute used to mark handler classes |
| dispatchMethods[] | Method names used to dispatch messages |
| handlerMethods[] | Method names in handler classes |
| messageClassNamePatterns | Regex pattern to identify message classes |
| messageHandlerInterfaces[] | Interfaces that handler classes implement |
| messageInterfaces[] | Interfaces that message classes implement |
| projectRootNamespace | Root namespace for scanning classes |
| useNativeGoToDeclaration | Disable ctrl+click to go to handler service |
- asMessageHandlerAttribute
- FQCN of the attribute used to mark handler classes
- Default Value:
Symfony\Component\Messenger\Attribute\AsMessageHandler
- dispatchMethods[]
- Method names used to dispatch messages
- handlerMethods[]
- Method names in handler classes
- messageClassNamePatterns
- Regex pattern to identify message classes
- Default Value:
.*(Message|Command|Query|Event|Input)$
- messageHandlerInterfaces[]
- Interfaces that handler classes implement
- messageInterfaces[]
- Interfaces that message classes implement
- projectRootNamespace
- Root namespace for scanning classes
- Default Value:
\App
- useNativeGoToDeclaration
- Disable ctrl+click to go to handler service
- Default Value:
false
symfonyMessenger:
asMessageHandlerAttribute: Symfony\Component\Messenger\Attribute\AsMessageHandler
dispatchMethods:
- dispatch
- query
- command
- handle
handlerMethods:
- __invoke
- handle
messageClassNamePatterns: .*(Message|Command|Query|Event|Input)$
messageHandlerInterfaces:
- Symfony\Component\Messenger\Handler\MessageHandlerInterface
messageInterfaces:
- ''
projectRootNamespace: \App
useNativeGoToDeclaration: false| Property | Description |
|---|---|
| associates[] | Array of bidirectional navigation rules |
| associates[].classA | Regex pattern with named groups matching first class FQN |
| associates[].classB | Pattern for second class FQN using (?<groupName>.+) substitution from named groups |
| peers[] | Array of one-way navigation rules |
| peers[].source | Regex pattern with named groups matching source class FQN |
| peers[].target | Target class FQN pattern using (?<groupName>.+) substitution from named groups |
- associates[]
- Array of bidirectional navigation rules
- associates[].classA
- Regex pattern with named groups matching first class FQN
- Example:
\\App\\Tests\\Func\\(?<type>.*)\\Web\\(?<path>.*)\\ControllerTest
- associates[].classB
- Pattern for second class FQN using
(?<groupName>.+)substitution from named groups - Example:
\\App\\(?<type>.*)\\Web\\(?<path>.*)\\Controller
- Pattern for second class FQN using
- peers[]
- Array of one-way navigation rules
- peers[].source
- Regex pattern with named groups matching source class FQN
- peers[].target
- Target class FQN pattern using
(?<groupName>.+)substitution from named groups
- Target class FQN pattern using
peerNavigation:
associates:
- classA: \\App\\Tests\\Func\\(?<type>.*)\\Web\\(?<path>.*)\\ControllerTest
classB: \\App\\(?<type>.*)\\Web\\(?<path>.*)\\Controller
peers:
- source: ''
target: ''Note: Associates provide bidirectional navigation - you can navigate from classA to classB and vice versa.
Bidirectional Navigation between Entities and Repositories:
peerNavigation:
associates:
- classA: \\App\\Domain\\Entity\\(?<entity>.+)
classB: \\App\\Domain\\Repository\\(?<entity>.+)RepositoryBidirectional Navigation between Controllers and Services:
peerNavigation:
associates:
- classA: \\App\\Controller\\(?<controller>.+)Controller
classB: \\App\\Service\\(?<controller>.+)ServiceOne-way Navigation from Commands to CommandHandlers using Named Groups:
peerNavigation:
peers:
- source: \\App\\Application\\(?<domain>.+)\\Command\\(?<command>.+)Command
target: \\App\\Application\\(?<domain>.+)\\CommandHandler\\(?<command>.+)CommandHandlerOne-way Navigation from Queries to QueryHandlers:
peerNavigation:
peers:
- source: \\App\\Application\\(?<domain>.+)\\Query\\(?<query>.+)Query
target: \\App\\Application\\(?<domain>.+)\\QueryHandler\\(?<query>.+)QueryHandlerComplex Example with Multiple Named Groups:
peerNavigation:
peers:
- source: \\App\\(?<layer>Application|Domain)\\(?<module>.+)\\Entity\\(?<entity>.+)
target: \\App\\(?<layer>Application|Domain)\\(?<module>.+)\\Repository\\(?<entity>.+)Repository
associates:
- classA: \\App\\Domain\\(?<module>.+)\\Entity\\(?<entity>.+)
classB: \\App\\Domain\\(?<module>.+)\\Factory\\(?<entity>.+)Factory| Property | Description |
|---|---|
| rules[] | Array of navigation rules |
| rules[].actionType | How search is triggered |
| rules[].attributeFQCN | FQCN of the attribute searched |
| rules[].fileMask | File mask to search for attribute usages, separated by comma |
| rules[].formatterScript | A groovy script to reformat raw attribute value |
| rules[].isDefault | Is this rule the default one? |
| rules[].propertyName | Property of the attribute used |
- rules[]
- Array of navigation rules
- rules[].actionType
- How search is triggered
- Default Value:
find_in_file
- rules[].attributeFQCN
- FQCN of the attribute searched
- Default Value:
\Symfony\Component\Routing\Attribute\Route
- rules[].fileMask
- File mask to search for attribute usages, separated by comma
- Default Value:
*.yaml,*.yml,*.php
- rules[].formatterScript
- A groovy script to reformat raw attribute value
- Example:
return (value.replaceAll("(\\{.*?\\})", "[^/]*")+ ":");
- rules[].isDefault
- Is this rule the default one?
- Default Value:
true
- rules[].propertyName
- Property of the attribute used
- Default Value:
path
attributeNavigation:
rules:
- attributeFQCN: \Symfony\Component\Routing\Attribute\Route
propertyName: path
isDefault: true
fileMask: '*.yaml,*.yml,*.php'
actionType: find_in_file
formatterScript: "\n return (value.replaceAll(\"(\\\\{.*?\\\\})\", \"[^/]*\"\
)+ \":\");\n "| Property | Description |
|---|---|
| contextualNamespaces[] | List of namespaces, if an import detected in an exported classes belong to one of those namespace, than the class is added in the context |
| template | Template Thymeleaf used to generate markdown export. Accès aux variables : files (FileData properties path, content, et extension) |
| useContextualNamespaces | Are contextual namespaces used? |
| useIgnoreFile | Are ignored files used? |
- contextualNamespaces[]
- List of namespaces, if an import detected in an exported classes belong to one of those namespace, than the class is added in the context
- template
- Template Thymeleaf used to generate markdown export. Accès aux variables :
files(FileData propertiespath,content, etextension) - Default Value: ``` [# th:each="file : ${files}"]
- Template Thymeleaf used to generate markdown export. Accès aux variables :
[(${file.content})]
[/]
- **useContextualNamespaces**
- Are contextual namespaces used?
- **Default Value**: ``` true ```
- **useIgnoreFile**
- Are ignored files used?
- **Default Value**: ``` true ```
<!-- generateDocumentationEnd -->
#### Example
<!-- generateDocumentationExample("org.micoli.php.exportSourceToMarkdown.configuration.ExportSourceToMarkdownConfiguration","exportSourceToMarkdown") -->
```yaml
exportSourceToMarkdown:
contextualNamespaces:
- App\Core\Models
template: |
[# th:each="file : ${files}"]
## [(${file.path})]
````[(${file.extension})]
[(${file.content})]
````
[/]
useContextualNamespaces: true
useIgnoreFile: true
| Property | Description |
|---|---|
| patterns[] | Regular expression pattern for parsing output (if pattern start with ^and finished with $, then the whole line is stripped out) |
- patterns[]
- Regular expression pattern for parsing output (if pattern start with ^and finished with $, then the whole line is stripped out)
consoleCleaner:
patterns:
- ''| Property | Description |
|---|---|
| attributeFQCN | Attribute used to detect routes |
| enabled | Enabler for panel of routes |
| namespaces[] | List of namespaces where routes are searched |
- attributeFQCN
- Attribute used to detect routes
- Default Value:
\Symfony\Component\Routing\Attribute\Route
- enabled
- Enabler for panel of routes
- Default Value:
true
- namespaces[]
- List of namespaces where routes are searched
routes:
attributeFQCN: \Symfony\Component\Routing\Attribute\Route
enabled: true
namespaces:
- \App
- \Application| Property | Description |
|---|---|
| attributeFQCN | Attribute used to detect console commands |
| enabled | Enabler for panel of console commands |
| namespaces[] | List of namespaces where console commands are searched |
- attributeFQCN
- Attribute used to detect console commands
- Default Value:
\Symfony\Component\Console\Attribute\AsCommand
- enabled
- Enabler for panel of console commands
- Default Value:
true
- namespaces[]
- List of namespaces where console commands are searched
commands:
attributeFQCN: \Symfony\Component\Console\Attribute\AsCommand
enabled: true
namespaces:
- \App
- \Application| Property | Description |
|---|---|
| attributeFQCN | Attribute used to detect Entities |
| enabled | Enabler for panel of doctrine entities |
| namespaces[] | List of namespaces where doctrine entities are searched |
- attributeFQCN
- Attribute used to detect Entities
- Default Value:
\Doctrine\ORM\Mapping\Table
- enabled
- Enabler for panel of doctrine entities
- Default Value:
true
- namespaces[]
- List of namespaces where doctrine entities are searched
doctrineEntities:
attributeFQCN: \Doctrine\ORM\Mapping\Table
enabled: true
namespaces:
- \Domain
- \Entity| Property | Description |
|---|---|
| enabled | Enabler for panel of OAS routes |
| specificationRoots[] | List of root files of swagger/openapi yaml/json files |
- enabled
- Enabler for panel of OAS routes
- Default Value:
true
- specificationRoots[]
- List of root files of swagger/openapi yaml/json files
openAPI:
enabled: true
specificationRoots:
- public/openapi.yaml
- private/openapi.yaml| Property | Description |
|---|---|
| enabled | Enabler for panel of Task and actions |
| tasks[] | Array of runnable task configurations available in the system. Each task must have a unique identifier to be referenced by tree or toolbar |
| tasks[].actionId | Builtin actionId to execute |
| tasks[].icon | Path to the icon to display for this builtin task. Uses standard IntelliJ Platform icons |
| tasks[].id | Unique task identifier used for references in tree and toolbar. Must be unique among all tasks in the configuration |
| tasks[].label | Label displayed to user in the interface. User-friendly name describing the task function |
| toolbar[] | Array of tasks to display in the toolbar for quick access. Each element must reference an existing task via its taskId |
| toolbar[].label | If set, it will overide task label in tree |
| toolbar[].taskId | Identifier of the referenced task. Must match the ID of an existing task in the TasksConfiguration tasks array |
| tree[] | Hierarchical tree structure of tasks and folders for organization in the user interface. Can contain Task objects (referencing tasks by ID) and Path objects (folders containing other nodes) |
| tree[].label | Label displayed for this folder in the hierarchical tree. User-friendly name for organizing tasks into logical groups |
| tree[].tasks[] | Array of child nodes contained in this folder. Can contain other folders (Path) or task references (Task) |
| watchers[] | File watchers configuration that automatically trigger tasks when specified files are modified |
| watchers[].debounce | Delay in milliseconds before task triggering after change detection. Prevents multiple executions during rapid successive modifications |
| watchers[].events | List all events triggering the watcher, by default, all events |
| watchers[].notify | Indicates if a notification should be displayed to the user upon triggering. False by default to avoid too frequent notifications |
| watchers[].taskId | Identifier of the task to execute when watched files are modified. Must match the ID of an existing task in the configuration |
| watchers[].watches[] | Array of file patterns to watch. Supports wildcards and regular expressions to match file paths |
- enabled
- Enabler for panel of Task and actions
- Example:
true - Default Value:
false
- tasks[]
- Array of runnable task configurations available in the system. Each task must have a unique identifier to be referenced by tree or toolbar
- tasks[].actionId
- Builtin actionId to execute
- Example:
$Copy
- tasks[].icon
- Path to the icon to display for this builtin task. Uses standard IntelliJ Platform icons
- Default Value:
debugger/threadRunning.svg
- tasks[].id
- Unique task identifier used for references in tree and toolbar. Must be unique among all tasks in the configuration
- Example:
aTaskId
- tasks[].label
- Label displayed to user in the interface. User-friendly name describing the task function
- Example:
First task
- toolbar[]
- Array of tasks to display in the toolbar for quick access. Each element must reference an existing task via its taskId
- toolbar[].label
- If set, it will overide task label in tree
- Example:
aLabel
- toolbar[].taskId
- Identifier of the referenced task. Must match the ID of an existing task in the TasksConfiguration tasks array
- Example:
aTaskId
- tree[]
- Hierarchical tree structure of tasks and folders for organization in the user interface. Can contain Task objects (referencing tasks by ID) and Path objects (folders containing other nodes)
- tree[].label
- Label displayed for this folder in the hierarchical tree. User-friendly name for organizing tasks into logical groups
- tree[].tasks[]
- Array of child nodes contained in this folder. Can contain other folders (Path) or task references (Task)
- watchers[]
- File watchers configuration that automatically trigger tasks when specified files are modified
- watchers[].debounce
- Delay in milliseconds before task triggering after change detection. Prevents multiple executions during rapid successive modifications
- Default Value:
1000
- watchers[].events
- List all events triggering the watcher, by default, all events
- watchers[].notify
- Indicates if a notification should be displayed to the user upon triggering. False by default to avoid too frequent notifications
- Default Value:
false
- watchers[].taskId
- Identifier of the task to execute when watched files are modified. Must match the ID of an existing task in the configuration
- watchers[].watches[]
- Array of file patterns to watch. Supports wildcards and regular expressions to match file paths
tasks:
enabled: false
tasks:
- type: builtin
id: aTaskId
label: null
actionId: $Copy
icon: debugger/threadRunning.svg
- type: shell
id: aTaskId
label: null
command: make clear-cache
cwd: ''
icon: debugger/threadRunning.svg
- type: script
id: aTaskId
label: null
source: ''
extension: groovy
icon: debugger/threadRunning.svg
- type: observedFile
id: aTaskId
label: null
commentPrefix: '#'
filePath: ''
variableName: ''
activeIcon: actions/inlayRenameInComments.svg
inactiveIcon: actions/inlayRenameInCommentsActive.svg
unknownIcon: expui/fileTypes/unknown.svg
postToggle:
type: builtin
id: aTaskId
label: null
actionId: null
icon: debugger/threadRunning.svg
- type: link
id: aTaskId
label: null
url: http://www.github.com
icon: expui/gutter/web.svg
- type: bookmark
id: aTaskId
label: null
path: http://www.github.com
icon: expui/gutter/web.svg
toolbar:
- type: task
taskId: aTaskId
label: aLabel
tree:
- type: path
label: ''
tasks:
- null
- null
- null
watchers:
- taskId: ''
debounce: 1000
notify: false
watches:
- ''
events:
- CREATE
- CONTENT_CHANGED
- COPY
- DELETE
- MOVE
- PROPERTY_CHANGED| Property | Description |
|---|---|
| enabled | Enabler for panel of SymfonyProfilers |
| excludeFilter[] | List of regular expression used to filter URI in profilers |
| profilerDataExportMode | Mode used to export data from Symfony Profiler (CLI or HTTP) |
| profilerPath | Local path to Symfony Profiler dumps |
| profilerProjectPath | Path to Symfony project root |
| profilerUrlRoot | Profiler URL root |
| urlRoots[] | List of URL roots of symfony profiles |
- enabled
- Enabler for panel of SymfonyProfilers
- Default Value:
false
- excludeFilter[]
- List of regular expression used to filter URI in profilers
- profilerDataExportMode
- Mode used to export data from Symfony Profiler (CLI or HTTP)
- Default Value:
HTTP
- profilerPath
- Local path to Symfony Profiler dumps
- Default Value:
var/cache/dev/profiler
- profilerProjectPath
- Path to Symfony project root
- profilerUrlRoot
- Profiler URL root
- Default Value:
https://127.0.0.1:8000/_profiler/
- urlRoots[]
- List of URL roots of symfony profiles
symfonyProfiler:
enabled: false
excludeFilter:
- ''
profilerDataExportMode: HTTP
profilerPath: var/cache/dev/profiler
profilerProjectPath: ''
profilerUrlRoot: https://127.0.0.1:8000/_profiler/
urlRoots:
- https://127.0.0.1:8000| Property | Description |
|---|---|
| enabled | Enabler for Php Class style configuration |
| rules[] | Array of rules to apply |
| rules[].fqcns[] | Fully Qualified class name or interface |
| rules[].style | Style to apply if class implements one of the FQCNs |
- enabled
- Enabler for Php Class style configuration
- Example:
true - Default Value:
false
- rules[]
- Array of rules to apply
- rules[].fqcns[]
- Fully Qualified class name or interface
- rules[].style
- Style to apply if class implements one of the FQCNs
styles:
enabled: false
rules:
- fqcns:
- ''
style:
foregroundColor: null
backgroundColor: null
fontStyles: []
effect: null
effectColor: null| Property | Description |
|---|---|
| enabled | Enabler for panel of Code style synchronization |
| styles[] | Array if code styles to synchronize |
| styles[].styleAttribute | Code style field property as in com.intellij.psi.codeStyle.CommonCodeStyleSettings |
| styles[].value | a boolean value true/false or an int value |
- enabled
- Enabler for panel of Code style synchronization
- Example:
true - Default Value:
false
- styles[]
- Array if code styles to synchronize
- styles[].styleAttribute
- Code style field property as in com.intellij.psi.codeStyle.CommonCodeStyleSettings
- Example:
ALIGN_MULTILINE_PARAMETERS_IN_CALLS
- styles[].value
- a boolean value true/false or an int value
- Example:
false
codeStyleSynchronization:
enabled: false
styles:
- styleAttribute: ALIGN_MULTILINE_PARAMETERS_IN_CALLS
value: 'false'-
runAction**
actionId: String
-
runActionInEditor**
actionId: String
-
clearPath**
path: String
-
clearPath**
path: StringmustBeGitIgnored: Boolean
-
alert**
message: String
-
alert**
message: StringdelayInMs: Int
- Named Groups: Use regex named groups
(?<name>...)in patterns and reference them with(?<name>...) (same expression)in targets for better readability and maintainability - Regex Escaping: In YAML configuration, use double backslashes (
\\) for namespace separators in regex patterns - Local Overrides: Use
.php-companion.local.*files for project-specific settings that shouldn't be committed - Hot Reload: The plugin checks for configuration changes every 2 seconds
- Error Handling: Configuration errors will be displayed as notifications in the IDE
- Peers vs Associates:
- Use
peersfor one-way navigation (source → target) - Use
associatesfor bidirectional navigation (classA ↔ classB)
- Use
- Pattern Matching: Both
peersandassociatessupport complex regex patterns with multiple named groups
- Java 11+
- IntelliJ IDEA with Plugin DevKit
- Gradle
# Build the plugin
./gradlew buildPlugin
# Run in development mode
./gradlew runIde
# Run tests
./gradlew test- ConfigurationFactory: Loads and merges configuration files
- GsonTools: Handles JSON object merging with conflict resolution
- Hot Reload: Automatic configuration reloading every 2 seconds
- MessengerService: Core service for message/handler detection and navigation
- MessengerGotoDeclarationHandler: Handles navigation from dispatch calls to handlers
- MessengerFindUsagesHandler: Finds all dispatch calls for messages/handlers
- PHPHelper: Utility methods for PHP class analysis
- PeerNavigationGotoDeclarationHandler: Handles navigation between peer classes
- Regex-based Matching: Flexible pattern matching for class relationships
- Fork the Repository: Create your own fork of the project
- Create Feature Branch:
git checkout -b feature/your-feature-name - Follow Code Style: Use existing code formatting and conventions
- Add Tests: Include unit tests for new functionality
- Update Documentation: Update README and inline documentation
- Submit Pull Request: Create a PR with clear description of changes
- Use standard Java naming conventions
- Add JavaDoc comments for public methods
- Keep methods focused and single-purpose
- Use meaningful variable and method names
- Handle exceptions appropriately with user-friendly error messages
The plugin includes unit tests for core functionality. When adding new features:
- Add corresponding unit tests
- Test with different PHP project structures
- Verify configuration loading and hot reload
- Test error handling scenarios
To debug the plugin:
- Use
./gradlew runIdeto launch a development instance - Set breakpoints in your IDE
- Use IntelliJ's internal logging:
Help → Show Log in Files - Enable debug notifications in
Notification.java
- Extension Points: Uses IntelliJ's extension point system for handlers
- Project Components: Manages lifecycle through ProjectComponent interface
- PSI Integration: Leverages PhpStorm's PSI (Program Structure Interface) for code analysis
- Background Processing: Configuration loading runs on background threads
- Event-Driven: Uses IntelliJ's event system for real-time updates
- Support for PHP 8 attributes parsing
- Enhanced caching for better performance
- Additional Symfony component integrations
- Visual configuration editor
- Code generation templates