How I use Live Templates in PHPStorm

TL,DR; By using Live Templates you can speed up writing the boilerplate part of a lot of code. Live Templates can be easily shared within a team. Examples of helpful live templates: when() and apply() methods, skeletons for value objects, skeletons for typed collections, incomplete test cases, wrappers for constructing value objects from string representations; These shortcuts will lower the barrier to experimentation within a team.

How fast you can type is usually not a constraint on software design work. However, having to write the same boilerplate code again, and again, and again can be quite a drag. Over the years I’ve started to use PHPStorm – my IDE of choice – better and better. One of its features is “Live Templates”. These can be used to generate small sections of code in particular types of contexts, like files, class bodies, method or function bodies.

The templates I have in my private collection fall in roughly these categories:

Copy and adapt

You can easily use and adapt the “Live Templates” shared below.

  1. Copy the XML snippet of the specific template
  2. Open PHPStorm
  3. Go to Preferences > Editor > Live Templates
  4. Select or create a folder to save the template
  5. Paste the snippet using CMD + V or CTRL + V
  6. Profit 😀

Sharing with your colleagues would follow a similar copy-paste path. It works remarkably well.

Generate methods that respond to events with typed signatures

These will be useful when parts of your domain model are event sourced.

Aggregate state mutator

Generates an apply*(* $event): void method signature. The focus of the caret will be at the 1st arguments type hint. Type the class name of your event here and the name of the method will be automatically update. This template compensates for the lack of method overloading in the PHP Language.

Type apply in the containing Aggregate class to invoke.

<template name="apply" value="protected function apply$EVENT$($TYPE$ $event): void {&#10;    $END$; // intentionally empty, none of the state is required for later decisions.&#10;}" description="Aggregate state mutator" toReformat="true" toShortenFQNames="true">
  <variable name="TYPE" expression="classNameComplete()" defaultValue="" alwaysStopAt="true" />
  <variable name="EVENT" expression="" defaultValue="TYPE" alwaysStopAt="false" />
  <context>
    <option name="PHP Class Member" value="true" />
  </context>
</template>

Projection and Process Manager event handler

Similar to the Aggregate state mutator but tailored towards a different interface signature.

Type when in the containing Projection or ProcessManager class to invoke.

<template name="when" value="private function when$EVENT$($TYPE$ $event): void {&#10;    $END$; // TODO: Implement when$TYPE$() method.&#10;}" description="Projection and Process Manager event handler" toReformat="true" toShortenFQNames="true">
  <variable name="TYPE" expression="classNameComplete()" defaultValue="" alwaysStopAt="true" />
  <variable name="EVENT" expression="" defaultValue="TYPE" alwaysStopAt="false" />
  <context>
    <option name="PHP Class Member" value="true" />
  </context>
</template>

Generate value object that encapsulates a scalar value in the form of a string

Let’s say you want to introduce a a value object for the Order Description. Generate the class OrderDescription and have this template generate the field, constructor, fromString and __toString methods.

Type svo in the containing ValueObject class to invoke.

<template name="svo" value="&#10;    private $$$FIELD_NAME$;&#10;&#10;    static function fromString (string $$$FIELD_NAME$): $TYPE$ { return new $TYPE$($$$FIELD_NAME$); }&#10;&#10;    private function __construct (string $$$FIELD_NAME$) { $this-&gt;$FIELD_NAME$ = $$$FIELD_NAME$; }&#10;&#10;    function __toString (): string { return $this-&gt;$FIELD_NAME$; }" description="Simple Value Object" toReformat="false" toShortenFQNames="true">
  <variable name="TYPE" expression="fileNameWithoutExtension()" defaultValue="" alwaysStopAt="false" />
  <variable name="FIELD_NAME" expression="camelCase(TYPE)" defaultValue="" alwaysStopAt="false" />
  <context>
    <option name="PHP Class Member" value="true" />
  </context>
</template>

Generate typed immutable collections

Imagine you run an e-commerce platform and you want to have a typed collection for OrderId value objects. Generate the class OrderIds and have this template generate a field, constructor, getIterator and count method. All you have to do is implement the Countable and IteratorAggregate interfaces.

Type coll in the containing Collection class to invoke.

<template name="coll" value="    private $$$FIELD$;&#10;&#10;    function __construct ($ENCAPSULATED_TYPE$ ... $$$FIELD$) { $this-&gt;$FIELD$ = $$$FIELD$; }&#10;&#10;    function count (): int { return count($this-&gt;$FIELD$); }&#10;&#10;    function getIterator (): \Traversable {&#10;        foreach ($this-&gt;$FIELD$ as $item)&#10;        {&#10;            yield $item;&#10;        }&#10;    }" description="Typed immutable collection" toReformat="true" toShortenFQNames="true">
  <variable name="ENCAPSULATED_TYPE" expression="classNameComplete()" defaultValue="" alwaysStopAt="true" />
  <variable name="FIELD" expression="" defaultValue="camelCase(fileNameWithoutExtension())" alwaysStopAt="false" />
  <context>
    <option name="PHP Class Member" value="true" />
  </context>
</template>

Wrap simple scalar values with a conventional fromString method call

Let’s say that you modeled the CartId as string but that you realized that there are actual business rules to it. First you introduce a CartId value object, which can be easily done with our Live Template. Then you start to find existing string representations like "Ab42Cd13" or $cartId and you select the literal or variable. Now you use this live template to wrap it with a fromString() call and you are asked for the class name of the value object in question.

Selecting a string literal or expression and type Command+Option+J to invoke.

<template name="fromString" value="$MODEL$::fromString($SELECTION$)" description="Construct value object" toReformat="true" toShortenFQNames="true">
  <variable name="MODEL" expression="classNameComplete()" defaultValue="" alwaysStopAt="true" />
  <context>
    <option name="PHP" value="true" />
    <option name="PHP Class Member" value="false" />
    <option name="PHP Comment" value="false" />
  </context>
</template>

Generate non-implemented test scenarios

The barrier to writing a test scenario should be as low as possible. Ideally we write out all conceivable scenarios and mark some as skipped with a clear explanation why we did not bother to write a test implementation. This communicates “Why” to the rest of the team. Now and in the future. So it is imperative that we can write tests fast.

Incomplete PHPUnit test case

Generates an empty non-implemented test scenario for a regular PHPUnit Framework Test Case. It uses an annotation so that the method name can be focused on describing the scenario.

Type ites in the containing TestCase class to invoke.

<template name="ites" value="/** @test */&#10;function $NAME$($PARAMETERS$): void {&#10;    $END$self::markTestIncomplete();&#10;}" description="Incomplete PHPUnit test case" toReformat="true" toShortenFQNames="true">
  <variable name="NAME" expression="" defaultValue="" alwaysStopAt="true" />
  <variable name="PARAMETERS" expression="" defaultValue="" alwaysStopAt="true" />
  <context>
    <option name="PHP Class Member" value="true" />
  </context>
</template>

Incomplete command handler test case for event sourced domain models

Generates an empty non-implemented test scenario for typical event sourced given, when, then scenario description. Will generate a when and then call on the scenario specification objects. You can easily call your event builders here and write simple tests. It uses an annotation so that the method name can be focused on describing the scenario.

Type chtes in the containing TestCase class to invoke.

<template name="chtes" value="/** @test */&#10;public function $NAME$($PARAMETERS$): void {&#10;    $this-&gt;scenarioToTest()&#10;        -&gt;when($COMMAND$)&#10;        -&gt;then($OUTCOME$)$END$&#10;    ;&#10;}" description="asdf" toReformat="true" toShortenFQNames="true">
  <variable name="NAME" expression="" defaultValue="" alwaysStopAt="true" />
  <variable name="PARAMETERS" expression="" defaultValue="" alwaysStopAt="true" />
  <variable name="COMMAND" expression="" defaultValue="" alwaysStopAt="true" />
  <variable name="OUTCOME" expression="" defaultValue="" alwaysStopAt="true" />
  <context>
    <option name="PHP Class Member" value="true" />
  </context>
</template>

You are working in the wrong language pal

Most of the templates I have compensate for a lack of features in PHP. So yes, you could argue that I should just move on and learn another language. As true as that may be, these templates will surely help some of the people that cannot or do not want to move on from PHP.

Conclusion: Use your IDE more

Live Templates can help you speed up the boring part of programming. Use your IDE to have your brain cycles applied to the domain problems that matter rather than looking for typos or waiting for your pairing partner to finish the “boilerplate” part of what you’re doing.

Funny thing. While researching for this post I discovered that there are useful templates for BASH and SQL and XSLT.

Disclaimer: I have never been compensated by JetBrains for my advocacy of their product nor will I accept any compensation in the future 😇.