Dependency Injection in Vanilla - HL Vanilla Community
<main> <article class="userContent"> <div class="embedExternal embedImage display-large float-none"> <div class="embedExternal-content"> <a class="embedImage-link" href="https://us.v-cdn.net/6030677/uploads/SCELY82A0LX7/microsoftteams-image-288-29.png" rel="nofollow noreferrer noopener ugc" target="_blank"> <img class="embedImage-img" src="https://us.v-cdn.net/6030677/uploads/SCELY82A0LX7/microsoftteams-image-288-29.png" alt="MicrosoftTeams-image (8).png" height="108" width="1356" loading="lazy" data-display-size="large" data-float="none"></img></a> </div> </div> <p>Vanilla uses <a href="https://github.com/vanilla/garden-container" rel="nofollow noreferrer ugc">garden-container</a> for dependency injection. The <code class="code codeInline" spellcheck="false" tabindex="0">\Garden\Container</code> object is a PSR-11 (Container Interface) compliant container class. This document outlines its usage in Vanilla, rather than how to use it, so it is worth reading the in-repo documentation.</p><h2 data-id="creating-container-rules">Creating Container Rules</h2><p>Vanilla has 3 core sets of container rules.</p><ul><li><code class="code codeInline" spellcheck="false" tabindex="0">Vanilla\Bootstrap</code> - Core container rules, shared between tests and production.</li><li><code class="code codeInline" spellcheck="false" tabindex="0">VanillaTests\Bootstrap</code> - Core container rules but only for tests.</li><li><code class="code codeInline" spellcheck="false" tabindex="0">bootstrap.php</code> Core container rules but only for production.</li></ul><p>Additionally addon's may define container rules as follows:</p><div class="js-embed embedResponsive" data-embedjson="{"body":"Vanilla makes heavy use of a dependency injection container. This document outlines how to configure it through an addon. Creating a ContainerRules Class This is the preferred way to configure an addon since the 2021.024 release. Create a new class in the Addon namespace of your addon. For example the dashboard container…","photoUrl":"https:\/\/us.v-cdn.net\/6030677\/uploads\/VWGAXAF5OFCO\/microsoftteams-image.png","url":"https:\/\/success.vanillaforums.com\/kb\/articles\/509-configuring-the-container-in-an-addon","embedType":"link","name":"Configuring the Container in an Addon - Vanilla Success"}"> <a href="https://success.vanillaforums.com/kb/articles/509-configuring-the-container-in-an-addon" rel="nofollow noreferrer ugc"> https://success.vanillaforums.com/kb/articles/509-configuring-the-container-in-an-addon </a> </div><h2 data-id="autowiring-dependencies">Autowiring Dependencies</h2><p><code class="code codeInline" spellcheck="false" tabindex="0">garden-container</code> autowires dependencies in the constructor. For example:</p><pre class="code codeBlock" spellcheck="false" tabindex="0">final class SomeController extends \Vanilla\Web\Controller { /** * @param SomeModel $someModel Model used to fetch some data in the controller. */ public function __construct(SomeModel $someModel) { // someModel } } </pre><p>Any instance of <code class="code codeInline" spellcheck="false" tabindex="0">SomeController</code> that is created through the container will have an instance of <code class="code codeInline" spellcheck="false" tabindex="0">SomeModel</code> passed in from the container. This is pretty straightforward from the perspective of a class with no sub-classes.</p><h2 data-id="injectableinterface">InjectableInterface</h2><p>When creating something that will be used as a base class though, we often do not want the constructors of our children to need to redeclare all of our dependencies.</p><p>This is where <code class="code codeInline" spellcheck="false" tabindex="0">\Vanilla\InjectableInterface</code> comes in. Vanilla’s container instance is pre-configured to call the <code class="code codeInline" spellcheck="false" tabindex="0">setDependencies()</code> method on any class implementing <code class="code codeInline" spellcheck="false" tabindex="0">InjectableInterface</code> with dependencies provided from the container.</p><p>Let’s look at an example with the <code class="code codeInline" spellcheck="false" tabindex="0">\Vanilla\Web\Controller</code>.</p><pre class="code codeBlock" spellcheck="false" tabindex="0">abstract class Controller implements InjectableInterface { // ... /** * Set the base dependencies of the controller. * * This method allows subclasses to declare their dependencies in their constructor without worrying about these * dependencies. * * @param SessionInterface|null $session The session of the current user. * @param EventManager|null $eventManager The event manager dependency. * @param LocaleInterface|null $local The current locale for translations. * @param Upload $upload File upload handler. */ public function setDependencies( SessionInterface $session = null, EventManager $eventManager = null, LocaleInterface $local = null, Upload $upload ) { $this->session = $session; $this->eventManager = $eventManager; $this->locale = $local; $this->upload = $upload; } //... } </pre><p>In this way our previous <code class="code codeInline" spellcheck="false" tabindex="0">SomeController</code> class does not need to redeclare all of these dependencies in it’s contstructor.</p><h2 data-id="gdn%3A%3Agetcontainer()">Gdn::getContainer()</h2><p>Sometimes you want to use a depedency injected class in one that is not autowired. An example of this would be implementing some new or updated functionality that must be introduced to an older system that cannot currently be dependency injected such as:</p><ul><li>Updating an old or deprecated global function.</li><li>Updating a static method that cannot have all of its call-sites replaced with an instance method.</li></ul><p><code class="code codeInline" spellcheck="false" tabindex="0">Gdn::getContainer()</code> will return the instance of the container statically. This practice is <strong><em>discouraged</em></strong>. Autowiring is preferred in any case possible.</p> </article> </main>