Save, version, and share custom SSR templates, with a Magento example against outdated ObjectManager calls
Structural Search and Replace finds code by its structure rather than by plain text, catching patterns a simple regex search would miss, for example regardless of variable names or formatting. The tool becomes truly powerful once a template built once is saved, named, and shared across the team instead of being rebuilt from scratch for every similar search. This article uses outdated Magento ObjectManager calls as an example to show how a team template comes together and stays usable long term.
Table of Contents
- 1. What sets Structural Search apart from a regex search
- 2. Building a custom search template in the Structural Search editor
- 3. Magento example: finding outdated ObjectManager::getInstance() calls
- 4. The matching replace template for automated refactoring
- 5. Saving, naming, and categorizing templates sensibly
- 6. Exporting templates and distributing them to the team
- 7. Versioning: the best place to keep templates in the project
- 8. Practical example: running a project-wide migration with SSR
- 9. SSR compared to Find and Replace and Rector
- 10. Summary
- 11. FAQ
1. What sets Structural Search apart from a regex search
A classic regex search works on plain text and has to anticipate variable names, whitespace, and order exactly, which quickly hits limits in real PHP code. Structural Search and Replace, SSR for short, instead works on the code's abstract syntax and recognizes patterns regardless of concrete identifiers.
An SSR template for a method call with an arbitrary object and an arbitrary argument reliably finds every variant across the whole project, whether the variable is called $product, $entity, or $model. It is exactly this independence from concrete names that makes SSR so valuable for project-wide refactorings.
This precision pays off especially for Magento modules maintained by rotating developers over the years, since naming conventions and code style there have often changed multiple times, and a plain text search inevitably misses matches.
2. Building a custom search template in the Structural Search editor
Edit, Find, Search Structurally opens the editor where a code snippet is entered as the pattern. Placeholders like $INSTANCE$ or $ARGS$ mark spots that should stay variable, while the rest of the code is matched exactly as written.
Through the filter button, each placeholder can additionally be restricted to a certain type or a certain count of occurrences, for example exactly one argument or an argument of type string. These filters make a template precise enough to avoid false positives in a real project.
For more complex patterns it helps to build the template step by step: first test a rough pattern without filters, review the match list, and then add filters deliberately until only the truly relevant spots remain in the result.
3. Magento example: finding outdated ObjectManager::getInstance() calls
Grown Magento projects frequently still contain direct calls to ObjectManager::getInstance(), even though constructor property promotion and dependency injection are the recommended path. An SSR template makes these spots visible project-wide, regardless of which class or method they sit in.
The search pattern captures both the direct assignment and the chained get call that follows, for example ObjectManager::getInstance()->get(ProductRepositoryInterface::class), and lists every match in its own search result tab, sorted by file.
// Search Template
\Magento\Framework\App\ObjectManager::getInstance()->get($CLASS$::class)
// $CLASS$ is freely configurable as a placeholder,
// Filter: Minimum count = 1, Maximum count = 1
4. The matching replace template for automated refactoring
Every search template pairs with a replace template that PhpStorm offers as a suggestion for each match when run. For the ObjectManager case, the call can be replaced with a comment pointing to the necessary manual switch to constructor injection, since a fully automatic switch would also touch the class's constructor.
For simpler cases, such as moving from array_key_exists to the null coalescing operator, the replace template can substitute the code directly and fully automatically. PhpStorm shows a diff preview before every application, so nothing is applied blindly.
For particularly sensitive code areas, such as the checkout or payment flow, it also helps to first apply the replace template only to a few deliberately chosen files and only extend it to the full set of matches after a successful test round.
// Replace Template
// TODO: replace ObjectManager::getInstance() with constructor injection for $CLASS$
$this->$CLASS_VAR$
5. Saving, naming, and categorizing templates sensibly
Save Template makes a pattern permanently available in the Structural Search Inspection toolbar or the Search Everywhere window. A descriptive name like Magento ObjectManager Direct Call, instead of a generic Template 1, makes it much easier to find again weeks later.
Templates can additionally be grouped into categories like Magento Legacy Patterns or Security Findings. This structure pays off especially once an entire set of recurring search patterns builds up over time, which would otherwise quickly become unwieldy.
A short description that PhpStorm optionally asks for when saving also helps understand a template's purpose months later without trying it out again, especially when several similar templates exist for related but not identical patterns.
6. Exporting templates and distributing them to the team
Saved SSR templates live locally in the PhpStorm configuration and are not automatically shared with the team by default. Through export they can be saved as a configuration file and then passed on to colleagues or placed into a shared storage repository.
Anyone using Settings Sync can additionally synchronize structural search templates through the personal category, but that only applies to their own account. For actual team distribution, explicit export is the more reliable path, since it works independently of the individual JetBrains account.
Teams that already maintain a central storage repository for internal tools should bundle the exported template files there together with other PhpStorm configuration files such as live templates or code style definitions, instead of keeping them scattered across different channels.
# Exported templates typically live under
~/.config/JetBrains/PhpStorm2025.2/options/structuralSearch.xml
# Storage in the project for team access
tools/phpstorm/ssr-templates/magento-objectmanager.xml
tools/phpstorm/ssr-templates/README.md
7. Versioning: the best place to keep templates in the project
Since PhpStorm does not automatically store SSR templates in the .idea folder, a dedicated directory in the project is recommended, for example tools/phpstorm/ssr-templates/, where the exported XML files are versioned together with a short README.
The README briefly describes what each template is for and how to import it, for example via Settings, Editor, Inspections, Structural Search Inspection, Import. This keeps the existing patterns traceable, even for a developer who has never used the particular template before.
A short version number or date in the exported template's filename additionally makes it easier to tell later whether a colleague has already imported an updated version, especially once a pattern has been refined over time.
8. Practical example: running a project-wide migration with SSR
When migrating an older Magento module to dependency injection, an SSR template first shows every affected spot across the whole app/code directory in a single results window, sorted by file and line, instead of searching each class individually.
The team then works through the list match by match, with the diff preview as a safety net before every change. For a migration spanning 40 files, this cuts the effort from a full day of manual searching down to a few hours of structured work.
// Before
class ProductImportProcessor
{
public function process(int $productId): void
{
$repository = \Magento\Framework\App\ObjectManager::getInstance()
->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
$repository->getById($productId);
}
}
// After, manually rewritten based on the SSR matches
final class ProductImportProcessor
{
public function __construct(
private readonly \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
) {
}
public function process(int $productId): void
{
$this->productRepository->getById($productId);
}
}
9. SSR compared to Find and Replace and Rector
Plain find and replace works on plain text and suits exact, unchanging character sequences, but fails as soon as variable names or formatting vary. Structural Search, in contrast, understands the code structure and stays accurate even with different naming.
Rector goes a step further and can run complex, multi line transformations fully automatically and headlessly in the CI pipeline, but requires its own rule definitions written in PHP and runs outside the IDE. For fast, interactive searches with immediate visual control, SSR in PhpStorm remains the more direct path.
For teams without prior Rector experience, SSR is often the more pragmatic entry point, since it delivers immediately visible results before investing in a dedicated, headless toolchain.
| Tool | Basis | Interactive in the IDE | Suited for CI |
|---|---|---|---|
| Structural Search and Replace | Abstract syntax | Yes, with diff preview | No, IDE bound |
| Find and Replace | Plain text or regex | Yes, very simple | Partly, via sed or grep |
| Rector | PHP AST, custom rules | No, headless | Yes, fully |
| PhpStorm refactorings | Semantic model | Yes, with preview | No, IDE bound |
Mironsoft
PhpStorm setup, Docker integration, and team productivity
PhpStorm that actually runs optimally for Magento and PHP projects?
We review existing PhpStorm setups for slow indexing, unused Docker integration, and missing team conventions, then set up a configuration that is productive from the first second.
Setup Review
Optimizing indexing, interpreter, and memory settings for large Magento projects.
Docker Integration
Cleanly connecting Xdebug, PHPUnit, and database tools to the Docker setup.
Team Conventions
Standardizing inspection profiles, code style, and live templates project-wide.
10. Summary
Structural Search Templates in a Team: The Essentials at a Glance
Structure over text
SSR recognizes code patterns regardless of variable names and formatting, unlike a classic regex search.
Save
A template gets saved with a descriptive name and stays findable that way across weeks and months.
Team sharing
Export as a configuration file plus storage in the project repository makes templates usable for the whole team.
Magento practice
A template against ObjectManager::getInstance() makes legacy spots visible project-wide immediately.