<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<title>@mteu · posts</title>
	<subtitle>Being me is full time job and I&#x27;ve never missed a day</subtitle>
	<link rel="self" type="application/atom+xml" href="https://mteu.cc/posts/feed.xml"/>
  <link rel="alternate" type="text/html" href="https://mteu.cc/posts/"/>
  
	<updated>2025-11-25T00:00:00+00:00</updated>
	
	<id>https://mteu.cc/posts/feed.xml</id>
	<entry xml:lang="en">
		<title>Type-Safe Extension Configuration in TYPO3</title>
		<published>2025-11-25T00:00:00+00:00</published>
		<updated>2025-11-25T00:00:00+00:00</updated>
		<link rel="alternate" type="text/html" href="https://mteu.cc/posts/announcing-typed-ext-conf/"/>
		<id>https://mteu.cc/posts/announcing-typed-ext-conf/</id>
    
		<content type="html" xml:base="https://mteu.cc/posts/announcing-typed-ext-conf/">&lt;p&gt;If you&#x27;ve spent any time building TYPO3 extensions, you&#x27;ve almost certainly bumped into the same frustration: extension configuration values are stored as strings. All of them. When a site administrator sets &lt;code&gt;maxItems&lt;&#x2F;code&gt; to &lt;code&gt;25&lt;&#x2F;code&gt; in the backend, your extension receives the string &lt;code&gt;&quot;25&quot;&lt;&#x2F;code&gt;. Need a boolean? You get &lt;code&gt;&quot;1&quot;&lt;&#x2F;code&gt; or &lt;code&gt;&quot;0&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;But the string problem is only half of it. Nothing stops a development team from overriding extension configuration values directly in &lt;code&gt;config&#x2F;system&#x2F;additional.php&lt;&#x2F;code&gt; — or anywhere else that writes into &lt;code&gt;$GLOBALS[&#x27;TYPO3_CONF_VARS&#x27;]&lt;&#x2F;code&gt;. When that happens, all bets are off. That &lt;code&gt;maxItems&lt;&#x2F;code&gt; value could now be an actual &lt;code&gt;int&lt;&#x2F;code&gt;, a &lt;code&gt;bool&lt;&#x2F;code&gt;, &lt;code&gt;null&lt;&#x2F;code&gt;, or something else entirely, depending on who wrote the override and when. Your extension is suddenly dealing with a mixed-type runtime reality it never agreed to.&lt;&#x2F;p&gt;
&lt;p&gt;The usual workarounds — custom wrapper classes, on-the-fly casting, &lt;code&gt;is_*&lt;&#x2F;code&gt; guards scattered across your codebase — are repetitive, error-prone, and still don&#x27;t protect you from unexpected types sneaking in through overrides.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s why I choose to offer a cleaner way to access extension configuration. So here&#x27;s me shamelessly advertising the TYPO3 extension &lt;strong&gt;Typed Extension Configuration&lt;&#x2F;strong&gt; v1.0 release:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer external&quot; href=&quot;https:&#x2F;&#x2F;extensions.typo3.org&#x2F;extension&#x2F;typed_extconf&quot;&gt;&lt;code&gt;EXT:typed_extconf&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; provides a somewhat type-safe extension configuration layer for TYPO3. You define your configuration as a plain PHP class with typed constructor parameters and a couple of attributes — the library handles reading, converting, and validating everything automagically:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;ExtensionConfig&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;extensionKey&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;my_extension&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;final&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt; readonly&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; MyExtensionConfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; __construct&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        #[&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;ExtConfProperty&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        public&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;maxItems&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        #[&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;ExtConfProperty&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        public&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;enableFeature&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        #[&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;ExtConfProperty&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;api.endpoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        public&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;apiEndpoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;api&#x2F;v1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then just type-hint the configuration class in your constructor — TYPO3&#x27;s DI container takes care of the rest:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;final&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; Foo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; __construct&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        private&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt; readonly&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; MyExtensionConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; doSomething&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; void&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;        $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;max&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;maxItems&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt; &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;        $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;enabled&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;enableFeature&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt; &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;        $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;apiEndpoint&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt; &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No casting, no manual parsing, no surprises — just clean, typed PHP.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;features&quot;&gt;Features&lt;a class=&quot;zola-anchor&quot; href=&quot;#features&quot; aria-label=&quot;Anchor link for: features&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Attribute-Based Schema: Define your configuration contract with &lt;code&gt;#[ExtensionConfig]&lt;&#x2F;code&gt; and &lt;code&gt;#[ExtConfProperty]&lt;&#x2F;code&gt;. Declarative, readable, and IDE-friendly.&lt;&#x2F;li&gt;
&lt;li&gt;Path Mapping: Map nested configuration keys with ease, e.g. &lt;code&gt;api.endpoint&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Configuration Generation: Run &lt;code&gt;.&#x2F;vendor&#x2F;bin&#x2F;typo3 typed-extconf:generate&lt;&#x2F;code&gt; to scaffold a configuration class from your existing &lt;code&gt;ext_conf_template.txt&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Dependency Injection: Configuration classes are auto-registered as services.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Under the hood, the library is powered by the amazing &lt;a rel=&quot;nofollow noreferrer external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;CuyZ&#x2F;Valinor&quot;&gt;CuyZ&#x2F;Valinor&lt;&#x2F;a&gt; for type-safe object mapping and validation — ensuring invalid or unexpected values are caught early, not deep inside your business logic.&lt;&#x2F;p&gt;
&lt;p&gt;The extension supports TYPO3 v12, v13, and v14 LTS. Full documentation, advanced examples, and a developer guide are available on &lt;a rel=&quot;nofollow noreferrer external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mteu&#x2F;typo3-typed-extconf&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
	</entry>
</feed>
