<p>You can use <a href="https://craftcms.com/docs/3.x/extend/extending-system-components.html#behaviors" rel="nofollow noreferrer">behaviors</a> to add new methods to system components. See the link above for documentation. A behavior is a class that extends <a href="https://www.yiiframework.com/doc/api/2.0/yii-base-behavior" rel="nofollow noreferrer">yii\base\Behavior</a> and is attached to a component using the <code>EVENT_DEFINE_BEHAVIORS</code> event.</p>
<p>First you define the class that provides your custom method:</p>
<pre class="lang-php prettyprint-override"><code>use yii\base\Behavior;

class FullNameBehavior extends Behavior {
    public function fullName() {
        return &quot;{$this-&gt;owner-&gt;firstName} {$this-&gt;owner-&gt;lastName}&quot;;
    }
}
</code></pre>
<p>The attach that behavior to the <code>Entry</code> class:</p>
<pre class="lang-php prettyprint-override"><code>use craft\elements\Entry;
use craft\events\DefineBehaviorsEvent;
use yii\base\Event;

// init() method in a module
Event::on(
    Entry::class,
    Entry::EVENT_DEFINE_BEHAVIORS,
    function (DefineBehaviorsEvent $e) {
        $e-&gt;sender-&gt;attachBehaviors([
            FullNameBehavior::class,
        ]);
    }
);
</code></pre>
<p>Now you can use the method in Twig:</p>
<pre class="lang-twig prettyprint-override"><code>{{ entry.fullName }}
</code></pre>
<p>You can put the behavior class and the event hook in a <a href="https://craftcms.com/docs/3.x/extend/module-guide.html#preparation" rel="nofollow noreferrer">module</a>.</p>
<h3>Alternative approaches</h3>
<p>I don't really like behaviors in general, as it's very hard to find out where their methods are defined if you don't know about them. Also, tacking endless additional methods onto a class that doesn't really have anything to do with them is kind of bad design.</p>
<p>Instead, consider the following solutions:</p>
<ul>
<li>Use a <a href="https://twig.symfony.com/doc/3.x/tags/macro.html" rel="nofollow noreferrer">macro</a> or a <a href="https://craftcms.com/docs/3.x/extend/extending-twig.html#register-a-twig-extension" rel="nofollow noreferrer">Twig filter or function</a> to display the full name consistently.</li>
<li>Install the <a href="https://plugins.craftcms.com/preparse-field" rel="nofollow noreferrer">Preparse Field</a> plugin and store the full name in a preparse field.</li>
<li>If feasible, you could represent people as <a href="https://craftcms.com/docs/3.x/users.html" rel="nofollow noreferrer">Users</a> instead of Entries – they come with a computed <a href="https://docs.craftcms.com/api/v3/craft-elements-user.html#fullname" rel="nofollow noreferrer">fullName property</a> by default.</li>
</ul>

CC BY-SA 4.0
2021-10-28T07:50:46.827Z
2021-10-28T07:50:46.827Z
MoritzLost
<p>What is the best practice for defining an attribute on an Entry that isn't persistent? For example, I want to create a formatted string from two separate values stored in fields on the entry, but don't need to store the computed value in a field or in the database.</p>
<p>I realize I can do this in a template variable like so:</p>
<p><code>{% set fullName = entry.firstName ~ &quot; &quot; ~ entry.lastName %}</code></p>
<p>... but, it would be much better if I could define this in a more global way so it can be used any time I'm dealing with an Entry within a specific Section like so:</p>
<p><code>{{ entry.fullName }}</code></p>
<p>I've read about custom Modules but that seems like overkill. Also, Craft may not offer any API to do something like this, but Yii might?</p>
<p>Halp.</p>

<entrymodel><attribute>
What's the best practice for creating computed (dynamic/virtual) attributes on entries?
# What's the best practice for creating computed (dynamic/virtual) attributes on entries?

(Asked by: username_0 on 2021-10-27)

What is the best practice for defining an attribute on an Entry that isn't persistent? For example, I want to create a formatted string from two separate values stored in fields on the entry, but don't need to store the computed value in a field or in the database.

I realize I can do this in a template variable like so:

`{% set fullName = entry.firstName ~ " " ~ entry.lastName %}`

... but, it would be much better if I could define this in a more global way so it can be used any time I'm dealing with an Entry within a specific Section like so:

`{{ entry.fullName }}`

I've read about custom Modules but that seems like overkill. Also, Craft may not offer any API to do something like this, but Yii might?

Halp.

**Tags:** entrymodel, attribute

---

## 1 answers

### Answer by username_1 on 2021-10-28. Score: 1

You can use behaviors to add new methods to system components. See the link above for documentation. A behavior is a class that extends yii\base\Behavior and is attached to a component using the EVENT_DEFINE_BEHAVIORS event.
First you define the class that provides your custom method:
use yii\base\Behavior;

class FullNameBehavior extends Behavior {
    public function fullName() {
        return "{$this->owner->firstName} {$this->owner->lastName}";
    }
}

The attach that behavior to the Entry class:
use craft\elements\Entry;
use craft\events\DefineBehaviorsEvent;
use yii\base\Event;

// init() method in a module
Event::on(
    Entry::class,
    Entry::EVENT_DEFINE_BEHAVIORS,
    function (DefineBehaviorsEvent $e) {
        $e->sender->attachBehaviors([
            FullNameBehavior::class,
        ]);
    }
);

Now you can use the method in Twig:
{{ entry.fullName }}

You can put the behavior class and the event hook in a module.
Alternative approaches
I don't really like behaviors in general, as it's very hard to find out where their methods are defined if you don't know about them. Also, tacking endless additional methods onto a class that doesn't really have anything to do with them is kind of bad design.
Instead, consider the following solutions:

Use a macro or a Twig filter or function to display the full name consistently.
Install the Preparse Field plugin and store the full name in a preparse field.
If feasible, you could represent people as Users instead of Entries – they come with a computed fullName property by default.


---

